Какая разница между '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.

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

Предыдущая расширенная демонстрация