Аксесори (гетер і сетер) у класах і об'єктах виглядають ззовні як звичайна властивість, але виконують код при читанні й записі.
class Temperature {
#celsius = 0;
get fahrenheit(): number {
return this.#celsius * 1.8 + 32;
}
set fahrenheit(value: number) {
this.#celsius = (value - 32) / 1.8;
}
}
Правила TypeScript:
- властивість лише з гетером автоматично
readonly- запис дає помилку; - з TypeScript 5.1 гетер і сетер можуть мати непов'язані типи (раніше тип гетера мусив бути сумісним з типом сетера).
Навіщо різні типи - сетер приймає ширше, гетер повертає нормалізоване:
class Field {
#value = '';
get value(): string {
return this.#value;
}
set value(input: string | number | null) {
this.#value = input === null ? '' : String(input);
}
}
const field = new Field();
field.value = 42; // дозволено
field.value.toUpperCase(); // завжди string
Так влаштовано чимало API браузера: властивість приймає ширший набір значень (рядок, null), а повертає нормалізований рядок. Опис таких API в .d.ts став точнішим саме завдяки цій можливості.
Те саме в інтерфейсах і типах об'єктів:
interface Thing {
get size(): number;
set size(value: number | string | boolean);
}
Ключове слово accessor (стандартні декоратори) - коротший запис поля з автоматичними гетером і сетером над прихованим сховищем: accessor count = 0. Корисне разом із декораторами, що перехоплюють доступ.
Що варто пам'ятати:
- дорогі гетери виглядають як дешеві поля - виклик у циклі може приховано коштувати багато;
- побічні ефекти в гетері - погана практика: читання не повинно змінювати стан;
- серіалізація:
JSON.stringifyне бачить гетерів класу (вони в прототипі) - потрібенtoJSON(); - поля проти аксесорів у нащадках: з
useDefineForClassFieldsполе в нащадку перекриває сетер батька - сетер не викликається.
Докладніше в документації: TypeScript 5.1: різні типи гетера й сетера