Menu

TypeScript extends: ein Interface oder einen Typ erweitern

Das Schlüsselwort extends baut einen Typ aus einem anderen. Wie du ein Interface erweiterst (einmal oder aus mehreren), einen Typalias mit & erweiterst, einen Eigenschaftstyp überschreibst, Eigenschaften mit Omit ersetzt und was extends in Klassen, Generic Constraints und Conditional Types bedeutet.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

interface Child extends Parent erzeugt ein neues Interface mit jedem Member von Parent plus seinen eigenen. Werte des Kindtyps lassen sich überall verwenden, wo die Eltern erwartet werden, weil sie alle deren Eigenschaften haben.

Dasselbe Schlüsselwort taucht in TypeScript an vier Stellen auf, mit verwandten, aber unterschiedlichen Bedeutungen:

WoBeispielBedeutung
Interfaceinterface Dog extends Animal {}die Member der Eltern erben
Klasseclass Dog extends Animal {}Felder und Methodenimplementierungen erben (JavaScript zur Laufzeit)
Generischer Parameter<T extends Animal>Constraint: Das Typargument muss Animal zuweisbar sein
Conditional TypeT extends string ? A : BTest: Ist T string zuweisbar?

Mehrere Interfaces erweitern

Führe mehrere Eltern nach extends auf, durch Kommas getrennt. Das Ergebnis hat die Member aller:

interface Identified {
  id: number;
}

interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface Post extends Identified, Timestamped {
  title: string;
}

// Post requires id, createdAt, updatedAt and title

Deklarieren zwei Eltern dieselbe Eigenschaft mit nicht identischen Typen, ist das Kind der Fehler TS2320 (Interface 'Post' cannot simultaneously extend types 'A' and 'B'), außer das Kind deklariert diese Eigenschaft neu mit einem Typ, der beiden zuweisbar ist.

Einen Typalias erweitern

Ein Alias type hat keine extends-Klausel. Du baust mit einer Intersection, &, darauf auf, die die Member beider Seiten kombiniert. Ein Interface kann einen Typalias für einen Objekttyp auch direkt erweitern, und ein Typalias kann ein Interface schneiden: Die beiden Arten lassen sich frei mischen.

Beide Wege verhalten sich gleich, bis Eigenschaften kollidieren: extends meldet eine widersprüchliche Eigenschaft an der Deklaration, während & sie stillschweigend zu never macht. Der Vergleich steht auf der Seite interface vs type, die Details zu & auf der Seite zu Intersection-Typen.

Eigenschaftstypen überschreiben

Ein Kind-Interface darf eine Eigenschaft der Eltern neu deklarieren, aber nur mit einem Typ, der dem der Eltern zuweisbar ist. string auf ein Literal einzuengen oder null aus einer Union zu entfernen ist erlaubt. Den Typ auf etwas Fremdes zu ändern nicht:

index.ts(13,11): error TS2430: Interface 'Label' incorrectly extends interface 'Shape'.
  Types of property 'kind' are incompatible.
    Type 'number' is not assignable to type 'string'.

Die Regel existiert, damit ein Label weiterhin überall verwendet werden kann, wo ein Shape erwartet wird. Könnte kind eine Zahl sein, würde Code, der für Shape geschrieben ist und shape.kind.toUpperCase() aufruft, kaputtgehen.

Eigenschaften mit Omit ersetzen

Brauchst du für eine geerbte Eigenschaft wirklich einen anderen Typ, entferne sie zuerst mit Omit aus den Eltern und deklariere dann die neue. Ein häufiger Fall ist das Umwandeln von API-Daten, bei denen IDs und Datumswerte als Strings ankommen:

Omit<ApiUser, "id" | "createdAt"> ist { name: string }, also kollidieren die neuen id und createdAt mit nichts. Pick, Partial und die anderen Utility Types lassen sich genauso erweitern.

extends bei Klassen

class Dog extends Animal ist Klassenvererbung von JavaScript und existiert anders als extends bei Interfaces zur Laufzeit: Dog bekommt den Konstruktor, die Felder und die Methodenimplementierungen von Animal, und new Dog(...) instanceof Animal ist true. TypeScript ergänzt darauf Typprüfungen, etwa das Schlüsselwort override:

Eine Klasse kann mit extends nur eine Klasse erweitern, aber mit implements beliebig viele Interfaces implementieren. implements kopiert nichts: Es prüft nur, dass die Klasse deklariert, was das Interface verlangt. super, protected Member und override werden unter Vererbung behandelt.

extends in Generics und Conditional Types

In spitzen Klammern ist extends ein Constraint. <T extends { length: number }> akzeptiert jedes Typargument mit numerischem length und erlaubt dem Funktionsrumpf, .length zu verwenden. In einem Conditional Type fragt T extends U ? X : Y, ob T U zuweisbar ist.

An beiden Stellen bedeutet extends „ist zuweisbar an“, dieselbe Beziehung, die die Interface-Form prüft. Constraints werden ausführlich unter Generic Constraints behandelt, Tests auf Typebene unter Conditional Types.

Häufig gestellte Fragen

Wie erweitert man in TypeScript ein Interface?

Schreibe interface Child extends Parent { ... }. Das Kind hat jede Eigenschaft der Eltern plus die, die es selbst deklariert. Um mehrere Interfaces auf einmal zu erweitern, trenne sie durch Kommas: interface C extends A, B { ... }.

Wie erweitert man in TypeScript einen Typalias?

Ein Typalias kann kein extends verwenden; kombiniere Typen stattdessen mit einer Intersection: type Admin = User & { permissions: string[] }. Ein Interface kann einen Typalias für einen Objekttyp auch direkt erweitern: interface Admin extends User { permissions: string[] }.

Kann ich beim Erweitern eines Interfaces einen Eigenschaftstyp überschreiben?

Nur mit einem kompatiblen, engeren Typ: kind: "circle" kann kind: string ersetzen. Ein anderer Typ, etwa number für eine string-Eigenschaft, ist der Fehler TS2430 (Interface 'X' incorrectly extends interface 'Y'). Um eine Eigenschaft durch einen fremden Typ zu ersetzen, entferne sie zuerst: interface User extends Omit<ApiUser, "id"> { id: number }.

Was ist der Unterschied zwischen extends und implements?

extends erbt: Ein Interface bekommt die Member der Eltern, und eine Klasse bekommt die Felder und Methodenimplementierungen der Elternklasse. implements prüft nur: Eine Klasse, die ein Interface implementiert, muss jeden Member selbst deklarieren und gewinnt nichts durch das Interface.

Was bedeutet extends in einem Generic wie <T extends string>?

Es ist ein Constraint, keine Vererbung. T extends string bedeutet, dass das Typargument string zuweisbar sein muss, in der Funktion kannst du auf T also String-Methoden verwenden. In einem Conditional Type ist T extends U ? X : Y ein Test: Ist T U zuweisbar, ist das Ergebnis X, sonst Y.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S