Коли клас-нащадок перевизначає метод батька, ззовні не видно, чи це свідоме перевизначення, чи збіг назв. А при рефакторингу батьківського класу перевизначення може тихо зламатися.
Модифікатор override робить намір явним:
class Model {
toArray(): Record<string, unknown> { return {}; }
}
class User extends Model {
override toArray() {
return { ...super.toArray(), name: this.name };
}
}
Що перевіряє компілятор:
- метод з
overrideмусить існувати в батьківському класі. Якщо батьківськийtoArrayперейменували наtoObject, у нащадку з'являється помилка - замість тихо «осиротілого» методу, який більше ніхто не викликає; - з прапорцем
noImplicitOverride- навпаки: перевизначення безoverrideтеж стає помилкою («This member must have an 'override' modifier because it overrides a member in the base class»).
{ "compilerOptions": { "noImplicitOverride": true } }
Які помилки це ловить:
- перейменування в батьківському класі - нащадок продовжує «перевизначати» метод, якого вже немає;
- випадкове перевизначення - у нащадку додали метод
save(), не помітивши, що такий уже є в базовому класі, і зламали його логіку; - друкарські помилки -
toArary()зoverrideодразу дасть помилку.
Аналогія з PHP: атрибут #[\Override] з PHP 8.3 робить те саме - перевіряє, що метод справді перевизначає батьківський.
Що варто знати:
overrideпрацює для методів, властивостей і аксесорів;- для реалізації абстрактних членів
overrideдозволений, але навіть зnoImplicitOverrideне обов'язковий - багато команд усе одно пишуть його для однаковості; - модифікатор зникає при компіляції - на виконання не впливає.
Рекомендація: вмикати noImplicitOverride у проєктах, де є успадкування класів. Це ще один прапорець, який дешево ловить реальні помилки і не входить у strict.