extends - успадкування: клас отримує поля й методи батьківського класу (і їхню реалізацію), може їх перевизначити й доповнити.
class Model {
save() { /* загальна логіка збереження */ }
}
class Post extends Model {
title = '';
}
new Post().save(); // метод успадковано
Клас може успадковувати лише один клас.
implements - перевірка відповідності інтерфейсу. Клас обіцяє мати певні члени, але нічого не отримує - реалізацію треба написати самому:
interface Cacheable {
cacheKey(): string;
}
interface Serializable {
toJSON(): object;
}
class Product implements Cacheable, Serializable {
constructor(private id: number) {}
cacheKey() { return `product:${this.id}`; }
toJSON() { return { id: this.id }; }
}
Клас може реалізовувати кілька інтерфейсів.
Важливе непорозуміння: implements не змінює тип класу і не впливає на виведення типів його членів. Він лише перевіряє:
interface Checkable {
check(name: string): boolean;
}
class NameChecker implements Checkable {
check(s) { // s - неявно any, а не string з інтерфейсу!
return s.length > 0;
}
}
Параметр не отримує тип з інтерфейсу - його треба оголосити явно.
Структурна типізація: клас, який має потрібні методи, і так сумісний з інтерфейсом - навіть без implements. Ключове слово корисне як явний контракт: помилка з'являється в місці оголошення класу, а не там, де його десь передають.
Що обирати:
extends- коли є спільна реалізація, а нащадок справді «є різновидом» батька;implements- коли потрібен спільний контракт без спільного коду;- для повторного використання поведінки часто краща композиція (передати об'єкт-помічник), ніж глибокі ієрархії успадкування.
Інтерфейс може «розширювати» клас (interface X extends SomeClass) - береться лише його форма, разом із приватними членами, що на практиці трапляється рідко.