readonly и параметры-свойства
Модификатор readonly вы уже видели у свойств объектного типа. У поля класса он работает так же. В картинке с чертежом это номер дома на фасаде. Его прикрепляют, пока дом строят, и потом не перевешивают, иначе почта понесёт письма не туда.
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 150Разберём пример по строкам:
readonly id: numberобъявляет поле только для чтения.- Конструктор записывает в него
id, и это разрешено: номер вешают, пока дом строится. order.total = 150меняет обычное поле, и компилятор не возражает.- Программа печатает
7 150.
Запись в readonly-поле
Записать readonly-поле можно только в двух местах: в его объявлении и в конструкторе. Любая запись после этого — ошибка, будь то order.id = 8 снаружи или this.id = next в методе самого класса:
error TS2540: Cannot assign to 'id' because it is a read-only property.«Нельзя присвоить id, потому что это свойство только для чтения». Этот запрет проверяет только tsc. В JavaScript id останется обычным полем, и при запуске запись сработает.
Параметры-свойства
Посмотрите на класс Order ещё раз: имя id в нём написано трижды. Сначала объявление поля, потом параметр конструктора, потом присваивание this.id = id. Чем больше полей, тем больше такого повторения.
В TypeScript для этого есть сокращение. Параметр-свойство — это параметр конструктора с модификатором public, private, protected или readonly. Такой параметр сразу объявляет поле с тем же именем и кладёт в него аргумент:
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 annaРазберём конструктор по частям:
private readonly id: numberобъявляет закрытое полеidтолько для чтения;public login: stringобъявляет открытое полеlogin, и словоpublicздесь обязательно: без модификатора параметр остался бы обычным параметром;- тело конструктора пустое: присваивания
tscнапишет сам.
Вот JavaScript, который tsc пишет из этого файла:
"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 annaВ коде появились объявления полей id и login и два присваивания в конструкторе. Их не было в файле .ts: tsc дописал их сам.
На собеседовании о параметрах-свойствах спрашивают так: что создаёт constructor(private name: string) {}? Ответ: закрытое поле name и присваивание ему аргумента.
node file.ts их не запустит
Обычно, чтобы получить JavaScript, из файла достаточно вырезать типы. С параметрами-свойствами так не выйдет: нужно дописать новые строки. Поэтому node user.ts, который умеет только вырезать типы, отказывается запускать такой файл:
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter property is not supported in strip-only modeОшибки в коде нет, и tsc его компилирует. Скомпилируйте файл через tsc user.ts и запустите node user.js или проверьте код в TypeScript Playground.
Если проект запускают через node file.ts, параметры-свойства в нём не пишут: поля объявляют и присваивают, как в классе Order.
Частая ошибка
Модификатор у параметра забыли:
class User {
constructor(login: string) {}
describe(): string {
return this.login; // ✗
}
}error TS2339: Property 'login' does not exist on type 'User'.Без модификатора login — обычный параметр: он живёт только внутри конструктора, и поля из него не получается. Допишите модификатор: constructor(public login: string) {}.
Главное
readonly-поле записывают в объявлении или в конструкторе, а потом только читают: иначе будет ошибкаTS2540.- Параметр конструктора с
public,private,protectedилиreadonlyстановится полем, и присваиваниеtscпишет сам. - Параметр без модификатора остаётся обычным параметром и полем не становится.
node file.tsне запускает файл с параметрами-свойствами: нуженtscили Playground.