readonly and parameter properties
You have already seen the readonly modifier on the properties of an object type. On a class field it works the same way. In the blueprint picture it is the house number on the front. It is put up while the house is being built and is never moved afterward, or the mail would go to the wrong place.
class Order {
readonly id: number;
total = 0;
constructor(id: number) {
this.id = id;
}
}
const order = new Order(7);
order.total = 150;
console.log(order.id, order.total); // 7 150Let's go through the example line by line:
readonly id: numberdeclares a read-only field.- The constructor writes
idinto it, and that is allowed: the number goes up while the house is being built. order.total = 150changes an ordinary field, and the compiler does not object.- The program prints
7 150.
Writing to a readonly field
A readonly field can be written in only two places: in its declaration and in the constructor. Any write after that is an error, whether it is order.id = 8 outside or this.id = next in a method of the class itself:
error TS2540: Cannot assign to 'id' because it is a read-only property."You cannot assign to id because it is a read-only property." Only tsc checks this rule. In the JavaScript id stays an ordinary field, and at run time the write works.
Parameter properties
Look at the class Order again: the name id is written in it three times. First the field declaration, then the constructor parameter, then the assignment this.id = id. The more fields there are, the more of this repetition you get.
TypeScript has a shorthand for it. A parameter property is a constructor parameter with the modifier public, private, protected or readonly. Such a parameter declares a field with the same name and puts the argument into it:
class User {
constructor(private readonly id: number, public login: string) {}
describe(): string {
return `${this.id}: ${this.login}`;
}
}
const user = new User(7, "anna");
console.log(user.describe(), user.login); // 7: anna annaLet's take the constructor apart:
private readonly id: numberdeclares a private read-only fieldid;public login: stringdeclares a public fieldlogin, and the wordpublicis required here: without a modifier the parameter would stay an ordinary parameter;- the constructor's body is empty:
tscwrites the assignments itself.
Here is the JavaScript tsc writes from this file:
"use strict";
class User {
id;
login;
constructor(id, login) {
this.id = id;
this.login = login;
}
describe() {
return `${this.id}: ${this.login}`;
}
}
const user = new User(7, "anna");
console.log(user.describe(), user.login); // 7: anna annaThe code has gained the field declarations id and login and two assignments in the constructor. They were not in the .ts file: tsc added them itself.
Interviewers ask about parameter properties like this: what does constructor(private name: string) {} create? The answer: a private field name and an assignment of the argument to it.
node file.ts will not run them
Usually, to get JavaScript, it is enough to cut the types out of a file. With parameter properties that does not work: new lines have to be written. That is why node user.ts, which can only cut types out, refuses to run such a file:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter property is not supported in strip-only modeThe code has no error, and tsc compiles it. Compile the file with tsc user.ts and run node user.js, or try the code in the TypeScript Playground.
If a project is run with node file.ts, it does without parameter properties: fields are declared and assigned as in the class Order.
Common mistake
The modifier on the parameter was forgotten:
class User {
constructor(login: string) {}
describe(): string {
return this.login; // ✗
}
}error TS2339: Property 'login' does not exist on type 'User'.Without a modifier login is an ordinary parameter: it lives only inside the constructor, and no field comes of it. Add the modifier: constructor(public login: string) {}.
Key points
- A
readonlyfield is written in its declaration or in the constructor and only read after that, otherwise you get errorTS2540. - A constructor parameter with
public,private,protectedorreadonlybecomes a field, andtscwrites the assignment itself. - A parameter without a modifier stays an ordinary parameter and does not become a field.
node file.tsdoes not run a file with parameter properties: you needtscor the Playground.