Модификатор override

Механизм наследования, особенно при написании так называемых библиотек, позволяет реализовать большую часть необходимого функционала в суперклассах, что значительно сокращает время разработки. Но при работе с наследованием можно встретить острые углы, сгладить которые в TypeScript предполагается за счёт оператора override опции компилятора --noImplicitOverride, которым и будет посвящена эта глава.

Модификатор override и флаг --noImplicitOverride

Представьте случай переопределения подклассом некоторых методов своего суперкласса.

ts
class SuperClass { /** * [*] Определяет метод */ a(){} // [*] b(){}// [*] } class SubClass extends SuperClass { /** * [*] Переопределяет методы своего суперкласса. */ a(){} // [*] b(){} // [*] }

Всё банально просто! Но что, если над проектом работает большое количество команд находящихся в разных уголках земного шара и команде занимающейся разработкой SuperClass неожиданно придеёт в голову изменить его api удалив оба метода? В таком случае, разработчики класса SubClass даже не узнают об этом, поскольку переопределение превратится в определение. Другими словами, компилятор даже глазом не моргнет, поскольку посчитает, что класс SubClass определят методы a() и b().

ts
class SuperClass { /** * Удалили a() и b() и добавили c(). */ с(){} } class SubClass extends SuperClass { /** * Ошибки не возникает, так как компилятор считает * что данный класс определяет оба метода. */ a(){} b(){} }

Для предотвращения подобных сценариев, в TypeScript существует модификатор override, который однозначно указывает на переопределение методов родительского класса. При использовании модификатора override компилятор сможет понять, что происходит переопределение несуществующих в суперклассе методов и сообщить об этом с помощью ошибки.

ts
class SuperClass { /** * Удалили a() и b() и добавили c(). */ с(){} } class SubClass extends SuperClass { /** * [*] Error -> * This member cannot have an 'override' modifier * because it is not declared in the base class 'SuperClass'.ts(4113) * * Теперь компилятор понимает, что происходи переопределение * несуществующих методов. */ override a(){} // [*] override b(){} // [*] }

Также при использовании механизма наследования может возникнуть диаметрально противоположная ситуация, при которой суперкласс может объявить метод, который уже существует в его потомке.

ts
/** * [0] метод определенный только в SubClass */ class SuperClass { a(){} } class SubClass extends SuperClass { b(){} // [0] } /** * [1] Но спустя некоторое время класс SuperClass * определяет метод b(), который уже существует в * классе-потомке [2]. Другими словами, произошло * нежелаемое переопределение способное привести * к непредсказуемому поведению программы. */ class SuperClass { a(){} b(){} // [1] } class SubClass extends SuperClass { b(){} // [2] }

Предотвратить нежелательное поведение в TypeScript можно с помощью флага --noImplicitOverride, при активации которого, в подобных случаях будет возникать ошибка.

ts
class SuperClass { a(){} b(){} } class SubClass extends SuperClass { /** * --noImplicitOverride = true * * [*] Error -> This member must have an 'override' * modifier because it overrides a member in the base * class 'SuperClass'.ts(4114) */ b(){} // [*] }