Одним из ключевых моментов объектно-ориентированной парадигмы является наследование. В TypeScript наследование реализуется с помощью ключевого слова extends (как в Java):
class Person { name: string; constructor(userName: string) { this.name = userName; } print(): void { console.log(`Имя: ${this.name}`); } } class Employee extends Person { company: string; work(): void { console.log(`${this.name} работает в компании ${this.company}`); } }
Класс Employee, который представляет работника, является подклассом или наследуется от класса Person. А класс Person называется родительским или базовым классом. При наследовании класс Employee перенимает весь функционал класса Person - все его свойства и функции и может их использовать. И также можно определить в подклассе новые свойства и методы, которых нет в классе Person.
let bob: Employee = new Employee("Bob"); bob.print();
Также мы можем расширить функциональность класса следующим образом:
class Person { name: string; constructor(userName: string) { this.name = userName; } print(): void { console.log(`Имя: ${this.name}`); } } class Employee extends Person { company: string; work(): void { console.log(`${this.name} работает в компании ${this.company}`); } } let bob: Employee = new Employee("Bob"); bob.print(); bob.company = "Microsoft"; bob.work();
Если подкласс определяет свой конструктор, то в нем должен быть вызван конструктор базового класса с помощью ключевого слова super:
class Person { name: string; constructor(userName: string) { this.name = userName; } print(): void { console.log(`Имя: ${this.name}`); } } class Employee extends Person { company: string; constructor(name: string, company: string) { super(name); this.company = company; } work(): void { console.log(`${this.name} работает в компании ${this.company}`); } } let bob: Employee = new Employee("Bob", "Microsoft"); bob.work(); // Bob работает в компании Microsoft
С помощью ключевого слова super подкласс может обратиться к функционалу базового класса. В данном случае
идет обращение к конструктору класса Person, который устанавливает значение свойства name: super(name)
Причем даже если базовый класс не определяет явным образом никакого конструктора, в производном классе при определении
конструктора все равно надо вызывать конструктор базового класса - в этом случае это будет вызов конструктора по умолчанию с помощью super()
.
class Person { name: string; } class Employee extends Person { company: string; constructor(name: string, company: string) { super(); // вызов конструктора базового класса this.name = name; this.company = company; } work(): void { console.log(`${this.name} работает в компании ${this.company}`); } } let bob: Employee = new Employee("Bob", "Microsoft"); bob.work(); // Bob работает в компании Microsoft
Также производные классы могут переопределять методы базовых классов:
class Person { name: string; constructor(name: string) { this.name = name; } print(): void { console.log(`Имя: ${this.name}`); } } class Employee extends Person { company: string; constructor(name: string, company: string) { super(name); this.company = company; } print(): void { console.log(`Имя: ${this.name}`); console.log(`Работает в компании: ${this.company}`); } } let bob: Employee = new Employee("Bob", "Microsoft"); bob.print();
В данном случае переопределяется метод print()
, который кроме имени выводит также компанию сотрудника. Однако в данном случае реализация метода
print()
из базового класса повторяется в производном классе. И вместо того, чтобы дублировть код, мы можем с помощью ключевого слова super
вызвать реализацию этого метода из базового класса:
class Person { name: string; constructor(name: string) { this.name = name; } print(): void { console.log(`Имя: ${this.name}`); } } class Employee extends Person { company: string; constructor(name: string, company: string) { super(name); this.company = company; } print(): void { super.print(); console.log(`Работает в компании: ${this.company}`); } } let bob: Employee = new Employee("Bob", "Microsoft"); bob.print();