Какая разница между 'extends' и 'tools' в TypeScript
Я хотел бы знать, что у man и child есть и как они отличаются.
class Person {
name: string;
age: number;
}
child extends Person {}
man implements Person{}
Ответы
Ответ 1
Документация должна помочь здесь:
Когда тип интерфейса расширяет тип класса, он наследует членов класса, но не их реализации. Это как если бы интерфейс объявили всех членов класса, не предоставив реализация. Интерфейсы наследуют даже частные и защищенные членов базового класса. Это означает, что при создании интерфейса который расширяет класс с частными или защищенными членами, этот интерфейс тип может быть реализован только этим классом или подклассом.
Это полезно, если у вас есть большая иерархия наследования, но вы хотите указать, что ваш код работает только с подклассами, которые имеют определенные свойства. Подклассы не должны быть связаны помимо наследования из базового класса. Например:
class Control {
private state: any;
}
interface SelectableControl extends Control {
select(): void;
}
class Button extends Control {
select() { }
}
class TextBox extends Control {
select() { }
}
class Image extends Control {
}
class Location {
select() { }
}
Итак, пока
-
extends
означает - он получает все из своего родителя
-
implements
в этом случае почти как реализация интерфейса. Детский объект может притворяться, что он является родителем.. но он не получает никакой реализации.
Ответ 2
В typescript (и некоторых других языках OO) у вас есть классы и интерфейсы.
Интерфейс не имеет реализации, это всего лишь "контракт" того, какие члены/метод имеет этот тип.
Например:
interface Point {
x: number;
y: number;
distance(other: Point): number;
}
Экземпляры, которые реализуют этот интерфейс Point
, должны иметь два члена типа: x
и y
, а один метод distance
, который получает другой экземпляр Point
и возвращает number
.
Интерфейс не реализует ни одного из них.
Классы - это реализации:
class PointImplementation implements Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public distance(other: Point): number {
return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
}
}
(код на игровой площадке)
В вашем примере вы относитесь к классу Person
один раз как к классу при его расширении и один раз в качестве интерфейса при его реализации.
Ваш код:
class Person {
name: string;
age: number;
}
class Child extends Person {}
class Man implements Person {}
Имеет ошибку компиляции:
Класс "Человек" неправильно реализует интерфейс "Человек" .
Свойство "имя" отсутствует в типе "Человек" .
И это потому, что интерфейсам не хватает реализации.
Поэтому, если вы implement
класс, тогда вы выполняете свой "контракт" без реализации, поэтому вам нужно будет сделать это:
class NoErrorMan implements Person {
name: string;
age: number;
}
(код на игровой площадке)
Нижняя строка состоит в том, что в большинстве случаев вы хотите extend
другой класс, а не implement
его.
Ответ 3
Отличный ответ от @nitzan-tomer! Помог мне много... Я немного расширил свою демонстрацию:
IPoint interface;
Point implements IPoint;
Point3D extends Point;
И как они ведут себя в функциях, ожидающих тип IPoint.
Итак, что я узнал до сих пор и использовал в качестве правила большого пальца: если вы используете классы и методы, ожидающие общие типы, используйте интерфейсы как ожидаемые типы. И убедитесь, что родительский или базовый класс использует этот интерфейс. Таким образом, вы можете использовать все подклассы в тех, которые реализуют интерфейс.
Предыдущая расширенная демонстрация