Модификатор override
Механизм наследования, особенно при написании так называемых библиотек, позволяет реализовать большую часть необходимого функционала в суперклассах, что значительно сокращает время разработки. Но при работе с наследованием можно встретить острые углы, сгладить которые в TypeScript предполагается за счёт оператора override
опции компилятора --noImplicitOverride
, которым и будет посвящена эта глава.
Модификатор override и флаг --noImplicitOverride
Представьте случай переопределения подклассом некоторых методов своего суперкласса.
class SuperClass {
/**
* [*] Определяет метод
*/
a(){} // [*]
b(){}// [*]
}
class SubClass extends SuperClass {
/**
* [*] Переопределяет методы своего суперкласса.
*/
a(){} // [*]
b(){} // [*]
}
Всё банально просто! Но что, если над проектом работает большое количество команд находящихся в разных уголках земного шара и команде занимающейся разработкой SuperClass
неожиданно придеёт в голову изменить его api удалив оба метода? В таком случае, разработчики класса SubClass
даже не узнают об этом, поскольку переопределение превратится в определение. Другими словами, компилятор даже глазом не моргнет, поскольку посчитает, что класс SubClass
определят методы a()
и b()
.
class SuperClass {
/**
* Удалили a() и b() и добавили c().
*/
с(){}
}
class SubClass extends SuperClass {
/**
* Ошибки не возникает, так как компилятор считает
* что данный класс определяет оба метода.
*/
a(){}
b(){}
}
Для предотвращения подобных сценариев, в TypeScript существует модификатор override
, который однозначно указывает на переопределение методов родительского класса. При использовании модификатора override
компилятор сможет понять, что происходит переопределение несуществующих в суперклассе методов и сообщить об этом с помощью ошибки.
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(){} // [*]
}
Также при использовании механизма наследования может возникнуть диаметрально противоположная ситуация, при которой суперкласс может объявить метод, который уже существует в его потомке.
/**
* [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
, при активации которого, в подобных случаях будет возникать ошибка.
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(){} // [*]
}