Наследование и implements
Два механизма связи классов: наследование поведения и обязательство соответствовать интерфейсу.
extendsнаследует поля и методы родителя;implementsобязывает класс соответствовать интерфейсу.
Наследование через extends
Дочерний класс получает поля и методы родителя и может их дополнять. Ключевое слово — extends:
class Animal {
constructor(protected name: string) {}
describe(): string {
return "Это " + this.name;
}
}
class Dog extends Animal {
bark(): string {
return this.name + " говорит: Гав!"; // name доступно — оно protected
}
}
const d = new Dog("Рекс");
console.log(d.describe()); // "Это Рекс" — метод от родителя
console.log(d.bark()); // "Рекс говорит: Гав!" — свой метод
Здесь видно, зачем нужен protected: поле name скрыто снаружи, но доступно в наследнике Dog. Будь оно private — bark не смог бы его прочитать.
super и переопределение
Дочерний класс может переопределить метод родителя и при этом вызвать оригинал через super:
class Cat extends Animal {
describe(): string {
return super.describe() + " — это кот";
}
}
console.log(new Cat("Барсик").describe()); // "Это Барсик — это кот"
Если у родителя конструктор с аргументами, в конструкторе наследника обязательно вызвать super(...) до обращения к this.
implements — контракт для класса
implements — другое: класс обязуется реализовать всё, что описано в интерфейсе. Интерфейс задаёт, что должен уметь класс, не диктуя как:
interface Shape {
area(): number;
perimeter(): number;
}
class Rectangle implements Shape {
constructor(private w: number, private h: number) {}
area(): number { return this.w * this.h; }
perimeter(): number { return 2 * (this.w + this.h); }
}
Если забыть метод из интерфейса, компилятор сразу укажет на это:
class Circle implements Shape {
constructor(private r: number) {}
area(): number { return Math.PI * this.r ** 2; }
// забыли perimeter()
}
// Ошибка: Class 'Circle' incorrectly implements interface 'Shape'. Property 'perimeter' is missing.
extends против implements
| extends | implements |
| наследует код (поля, методы) | обязывает реализовать методы |
| только один родитель | можно несколько интерфейсов |
| «является разновидностью» | «умеет делать» |
Один класс может одновременно наследоваться и реализовывать интерфейсы: class Dog extends Animal implements Serializable. Несколько интерфейсов перечисляют через запятую — это удобный способ задать классу несколько контрактов сразу.
Зачем это: взаимозаменяемость
Благодаря implements разные классы с одним интерфейсом взаимозаменяемы. Функция, принимающая Shape, работает с любой фигурой — и с Rectangle, и с Circle. Это основа гибкого, расширяемого кода.
Итог
extendsнаследует реализацию родителя;protected-поля доступны наследникам,superзовёт родительский метод.implementsобязывает класс реализовать методы интерфейса — пропуск ловится компилятором.- Класс наследует один класс, но может реализовать несколько интерфейсов; это делает объекты взаимозаменяемыми.