Was ist der Unterschied zwischen "Erweitert" und "Implementiert" in TypeScript?

Antworten:

152

Kurzfassung

  • extends meint:

Die neue Klasse ist ein Kind . Es bringt Vorteile mit der Vererbung. Es hat alle Eigenschaften und Methoden als übergeordnetes Element. Es kann einige davon überschreiben und neue implementieren, aber das übergeordnete Material ist bereits enthalten.

  • implements meint:

Die neue Klasse kann als dieselbe "Form" behandelt werden , obwohl sie kein Kind ist . Es kann an jede Methode übergeben werden, bei der dies Personerforderlich ist, unabhängig davon, ob ein anderes übergeordnetes Element als vorhanden istPerson

Mehr ...

In OOP (Sprachen wie C #, Java) würden wir verwenden

extendsvon der Vererbung profitieren (siehe Wiki ). Kleines Zitat:

... Die Vererbung in den meisten klassenbasierten objektorientierten Sprachen ist ein Mechanismus, bei dem ein Objekt alle Eigenschaften und Verhaltensweisen des übergeordneten Objekts erfasst. Durch Vererbung können Programmierer: Klassen erstellen, die auf vorhandenen Klassen aufbauen ...

implementswird mehr für Polymorphismus sein (siehe Wiki ). Kleines Zitat:

... Polymorphismus ist die Bereitstellung einer einzigen Schnittstelle zu Entitäten verschiedener Typen ...

Wir können also einen wirklich anderen Vererbungsbaum von uns haben class Man.

class Man extends Human ...

aber wenn wir auch erklären, dass wir vorgeben können, ein anderer Typ zu sein - Person:

class Man extends Human 
          implements Person ...

.. dann können wir es überall verwenden, wo das Personbenötigt wird. Wir müssen nur die von Personen erfüllen "interface" (dh alle öffentlichen Dinge implementieren) .

implementandere Klasse? Das ist wirklich cooles Zeug

Das schöne Gesicht von Javascript (einer der Vorteile) ist die integrierte Unterstützung der Enten-Eingabe ( siehe Wiki ). Kleines Zitat:

"Wenn es wie eine Ente läuft und wie eine Ente quakt, dann muss es eine Ente sein."

Wenn also in Javascript zwei verschiedene Objekte ... eine ähnliche Methode haben (z. B. render()) , können sie an eine Funktion übergeben werden, die dies erwartet:

function(engine){
  engine.render() // any type implementing render() can be passed
}

Um das nicht zu verlieren - wir können in Typescript dasselbe tun - mit mehr typisierter Unterstützung. Und dort ist

class implements class

hat seine Rolle, wo es Sinn macht

In OOP-Sprachen als C# ... keine Möglichkeit, das zu tun ...

Auch die Dokumentation soll hier helfen:

Schnittstellen, die Klassen erweitern

Wenn ein Schnittstellentyp einen Klassentyp erweitert, erbt er die Mitglieder der Klasse, jedoch nicht deren Implementierungen. Es ist, als hätte die Schnittstelle alle Mitglieder der Klasse deklariert, ohne eine Implementierung bereitzustellen. Schnittstellen erben sogar die privaten und geschützten Mitglieder einer Basisklasse. Dies bedeutet, dass beim Erstellen einer Schnittstelle, die eine Klasse mit privaten oder geschützten Mitgliedern erweitert, dieser Schnittstellentyp nur von dieser Klasse oder einer Unterklasse davon implementiert werden kann.

Dies ist nützlich, wenn Sie eine große Vererbungshierarchie haben, aber angeben möchten, dass Ihr Code nur mit Unterklassen mit bestimmten Eigenschaften funktioniert. Die Unterklassen müssen nicht miteinander verknüpft sein, außer von der Basisklasse zu erben. Beispielsweise:

class Control {
    private state: any;
}

interface SelectableControl extends Control {
    select(): void;
}

class Button extends Control implements SelectableControl {
    select() { }
}

class TextBox extends Control {
    select() { }
}

// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl {
    private state: any;
    select() { }
}

class Location {

}

Also, während

  • extends bedeutet - es bekommt alles von seinem Elternteil
  • implementsIn diesem Fall ist es fast so, als würde man eine Schnittstelle implementieren. Untergeordnetes Objekt kann so tun, als wäre es übergeordnet ... aber es wird nicht implementiert
Radim Köhler
quelle
Wenn Sie sagen " extends-es bekommt alles von seinem Elternteil", gilt es für private Mitglieder? Zum Beispiel class Person {private name: string} class man extends Person{gender: string;}hat mandie Eigenschaft Namen?
Davejoem
Privat sind auch da. Nur für TS unzugänglich. Machen Sie sie geschützt und Sie können sie verwenden. Bei "Geräten" ist nur der öffentliche Teil sinnvoll. Hoffe es hilft ein bisschen
Radim Köhler
Hervorragende Antwort. Nur nicht sicher durch Ihren Kommentar für "privat ist da, aber nicht zugänglich für TS". Meinen Sie damit, dass private Eigenschaften in dieses neu erstellte untergeordnete Objekt kopiert werden? Und bei Geräten werden nur öffentliche Objekte kopiert?
Kushalvm
Außerdem habe ich noch einen Punkt erreicht. Wenn dies die Definition von erweitert ist. Dann bitte, wenn Sie diesen stackoverflow.com/questions/60390454/…
kushalvm
96

In Typoskript (und einigen anderen OO-Sprachen) haben Sie Klassen und Schnittstellen.

Eine Schnittstelle hat keine Implementierung, es ist nur ein "Vertrag" darüber, welche Mitglieder / Methoden dieser Typ hat.
Beispielsweise:

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

Instanzen, die diese PointSchnittstelle implementieren , müssen zwei Mitglieder vom Typ number: xund yund eine Methode haben, distancedie eine andere PointInstanz empfängt und a zurückgibt number.
Die Schnittstelle implementiert keine davon.

Klassen sind die Implementierungen:

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));
    }
}

( Code auf dem Spielplatz )

In Ihrem Beispiel behandeln Sie Ihre PersonKlasse einmal als Klasse, wenn Sie sie erweitern, und einmal als Schnittstelle, wenn Sie sie implementieren.
Dein Code:

class Person {
    name: string;
    age: number;
}
class Child  extends Person {}

class Man implements Person {}

Hat einen Kompilierungsfehler, der sagt:

Die Klasse 'Man' implementiert die Schnittstelle 'Person' falsch.
Die Eigenschaft 'name' fehlt im Typ 'Man'.

Und das liegt daran, dass Schnittstellen nicht implementiert sind.
Wenn Sie also implementeine Klasse sind, nehmen Sie nur ihren "Vertrag" ohne die Implementierung, also müssen Sie dies tun:

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

( Code auf dem Spielplatz )

Fazit ist, dass Sie in den meisten Fällen zu einer extendanderen Klasse und nicht zu implementdieser wollen.

Nitzan Tomer
quelle
7
Diese Antwort ist einfacher zu verstehen.
Akshay Raut
6

Tolle Antwort von @ nitzan-tomer! Hat mir sehr geholfen ... Ich habe seine Demo ein wenig erweitert mit:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

Und wie sie sich in Funktionen verhalten, die einen IPointTyp erwarten .

Was ich bisher gelernt und als Faustregel verwendet habe: Wenn Sie Klassen und Methoden verwenden, die generische Typen erwarten, verwenden Sie Schnittstellen als erwartete Typen. Stellen Sie sicher, dass das übergeordnete Element oder die Basisklasse diese Schnittstelle verwendet. Auf diese Weise können Sie alle Unterklassen in diesen verwenden, sofern sie die Schnittstelle implementieren.

Hier die erweiterte Demo

andzep
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klarstellung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag. - Von der Überprüfung
aronisstav
1
@aronisstav Ich habe nur eine erweiterte Demo gepostet, von der ich eine gute Antwort gefunden habe, die mir bereits geholfen hat. Aber vielleicht würde jemand anderes die Arbeit, die ich zur Erweiterung der Demo geleistet habe, nützlich finden. Das ist alles. Kommentare sind nicht wirklich zum Einfügen eines Codeblocks gedacht, deshalb finde ich sie in einem Antwort-Post besser verständlich. Also, was ist das Problem damit?
Andzep
Ihre Antwort wurde (automatisch?) Aufgrund von Länge und Inhalt markiert, in meiner Überprüfungswarteschlange angezeigt und ich habe die in der Flagge angegebenen Gründe begründet. Der Hauptbeitrag (der erklärt, dass Sie die Demo erweitert haben) wäre besser als Kommentar. Mit dem hinzugefügten Absatz ist es vielleicht tatsächlich nützlicher.
Aronisstav
@andzep Ihr ​​erweitertes Demo-Beispiel ist wirklich hilfreich.
Namit
3
  1. Schnittstelle erweitert Schnittstelle mit Form
  2. Schnittstelle erweitert Klasse mit Form
  3. Klasse implementiert Schnittstelle sollte alle Felder implementieren, die von der Schnittstelle bereitgestellt werden
  4. Klasse implementiert Klasse mit Form
  5. Klasse erweitert Klasse mit allen Feldern

extendsKonzentrieren Sie sich auf das Erben und implementsauf Einschränkungen, ob Schnittstellen oder Klassen.

lei li
quelle
0

Erweitert VS-Geräte

  • extends: Die untergeordnete Klasse (die erweitert wird) erbt alle Eigenschaften und Methoden der erweiterten Klasse
  • implements: Die Klasse, die das implementsSchlüsselwort verwendet, muss alle Eigenschaften und Methoden der Klasse implementieren, die sie verwendetimplements

Einfacher ausgedrückt:

  • extends: Hier erhalten Sie alle diese Methoden / Eigenschaften von der übergeordneten Klasse, sodass Sie dies nicht selbst implementieren müssen
  • implements: Hier ist ein Vertrag, dem die Klasse folgen muss. Die Klasse muss mindestens die folgenden Methoden / Eigenschaften implementieren

Beispiel:

class Person {
  name: string;
  age: number;

  walk(): void {
    console.log('Walking (person Class)')
  }

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
class child extends Person { }

// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person {
  name: string;
  age: number

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  walk(): void {
    console.log('Walking (man class)')
  }

}

(new child('Mike', 12)).walk();
// logs: Walking(person Class)

(new man('Tom', 12)).walk();
// logs: Walking(man class)

Im Beispiel können wir beobachten, dass die untergeordnete Klasse alles von Person erbt, während die man-Klasse alles von Person selbst implementieren muss.

Wenn wir etwas aus der man-Klasse entfernen würden, zum Beispiel die walk-Methode, würden wir den folgenden Kompilierungszeitfehler erhalten :

Die Klasse 'man' implementiert die Klasse 'Person' falsch. Wollten Sie 'Person' erweitern und seine Mitglieder als Unterklasse erben? Die Eigenschaft 'walk' fehlt im Typ 'man', ist jedoch im Typ 'Person' erforderlich. (2720)

Willem van der Veen
quelle