В чем разница между "extends" и "implements" в TypeScript

Я хотел бы знать, что человек и ребенок имеют общее и как они отличаются.

class Person {
  name: string;
  age: number;
}
class child extends Person {}
class man implements Person {}

3 ответов


короткая версия

  • extends означает:

на новый класс-это ребенок. Он получает преимущества, связанные с наследством. Он имеет все свойства, методы как его родитель. Он может переопределить некоторые из них и реализовать новые, но Родительский материал уже включен.

  • implements означает:

на новый класс можно рассматривать как в же "формы", а это не ребенок. Он может быть передан любому методу, где Person требуется, независимо от наличия другого родителя, чем Person

больше ...

на ОП (такие языки, как C#, Java) мы будем использовать

extends получить прибыль от наследования (см. wiki). Маленький цитата:

... Наследование в большинство объектно-ориентированных языков на основе классов-это механизм, в котором один объект приобретает все свойства и поведение родительского объекта. Наследование позволяет создавать классы, которые строятся на основе существующих классов ...

implements будет больше для полиморфизма (см. wiki). Маленький цитата:

... полиморфизм-это предоставление единого интерфейса сущностям разных типы...

таким образом, мы можем иметь действительно различное дерево наследования нашего class Man.

class Man extends Human ...

но если мы также объявим, что мы можем притвориться другим типом - Person:

class Man extends Human 
          implements Person ...

.. тогда мы можем использовать его где угодно, где это. Мы просто должны выполнить Persons "interface" (т. е. реализовать все свои публичные вещи).

implement другой класс? Это действительно круто чушь!--21-->

Javascript хорошее лицо (одно из преимуществ) является встроенной поддержкой ввода утки (см. wiki). Маленький цитата:


в typescript (и некоторых других языках OO) у вас есть классы и интерфейсы.

интерфейс не имеет реализации, это просто "контракт" того, что имеет этот тип членов/метода.
Например:

interface Point {
    x: number;
    y: number;
    distance(other: Point): number;
}

экземпляры, которые реализуют этот Point интерфейс должен иметь два члена типа number: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 {}

имеет ошибку компиляции, говоря:

класс ' Man ' неправильно реализует интерфейс 'Person'.
Свойство "name" отсутствует в типе "Человек".

и это потому, что интерфейсы не реализованы.
Так что если вы implement класс, то вы только берете его "контракт" без реализации, поэтому вам нужно будет сделать это:

class NoErrorMan implements Person {
    name: string;
    age: number;
}

( код на игровой площадке)

суть в том, что в большинстве случаев вы хотите extend другой класс, а не implement его.


отличный ответ от @nitzan-tomer! Очень помогло... Я немного расширил его демо:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

и как они ведут себя в функциях, ожидающих тип IPoint.

Итак, что я узнал до сих пор и использовал в качестве правила большого пальца: если вы используете классы и методы, ожидающие универсальных типов, используйте интерфейсы в качестве ожидаемых типов. И убедитесь, что родительский или базовый класс использует этот интерфейс. Таким образом, вы можете использовать все подклассы в тех, насколько они реализуют взаимодействие.

Hier расширенная демо