Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як типізувати гетери й сетери і навіщо гетеру й сетеру різні типи?

Аксесори (гетер і сетер) у класах і об'єктах виглядають ззовні як звичайна властивість, але виконують код при читанні й записі.

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: різні типи гетера й сетера

Схожі питання