TypeScript: Schnittstellen vs Typen

Antworten:

574

Gemäß der TypeScript-Sprachspezifikation :

Im Gegensatz zu einer Schnittstellendeklaration, die immer einen benannten Objekttyp einführt, kann eine Typaliasdeklaration einen Namen für jede Art von Typ einführen, einschließlich Primitiv-, Vereinigungs- und Schnittpunkttypen.

In der Spezifikation wird weiter erwähnt:

Schnittstellentypen haben viele Ähnlichkeiten mit Typaliasen für Objekttypliterale, aber da Schnittstellentypen mehr Funktionen bieten, werden sie im Allgemeinen bevorzugt, um Aliase einzugeben. Zum Beispiel der Schnittstellentyp

interface Point {
    x: number;
    y: number;
}

könnte als Typalias geschrieben werden

type Point = {
    x: number;
    y: number;
};

Dies bedeutet jedoch, dass die folgenden Funktionen verloren gehen:

  • Eine Schnittstelle kann in einer Extended- oder Implementierungsklausel benannt werden, aber ein Typalias für ein Objekttypliteral kann seit TS 2.7 nicht mehr wahr sein.
  • Eine Schnittstelle kann mehrere zusammengeführte Deklarationen haben , ein Typalias für ein Objekttypliteral jedoch nicht.
Binäre Birke
quelle
109
Was bedeutet "mehrfach zusammengeführte Deklarationen" im zweiten Unterschied?
Jrahhali
66
@jrahhali Wenn Sie die Schnittstelle zweimal definieren, führt Typoskript sie zu einer zusammen.
Andrey Fedorov
39
@ jrahhali Wenn Sie Typ zweimal definieren, gibt Typoskript Ihnen Fehler
Andrey Fedorov
18
@ jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco
20
Ich glaube, der erste Punkt extends or implementsist nicht mehr der Fall. Typ kann erweitert und implementiert werden durch a class. Hier ist ein Beispiel typescriptlang.org/play/...
dark_ruby
776

Update 2019


Die aktuellen Antworten und die offizielle Dokumentation sind veraltet. Und für diejenigen, die neu in TypeScript sind, ist die verwendete Terminologie ohne Beispiele nicht klar. Nachfolgend finden Sie eine Liste der aktuellen Unterschiede.

1. Objekte / Funktionen

Beide können verwendet werden, um die Form eines Objekts oder eine Funktionssignatur zu beschreiben. Die Syntax ist jedoch unterschiedlich.

Schnittstelle

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}

Geben Sie einen Alias ​​ein

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;

2. Andere Typen

Im Gegensatz zu einer Schnittstelle kann der Typalias auch für andere Typen wie Grundelemente, Vereinigungen und Tupel verwendet werden.

// primitive
type Name = string;

// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union
type PartialPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];

3. Verlängern

Beide können erweitert werden, aber auch hier unterscheidet sich die Syntax. Beachten Sie außerdem, dass sich ein Schnittstellen- und Typalias nicht gegenseitig ausschließen. Eine Schnittstelle kann einen Typalias erweitern und umgekehrt.

Schnittstelle erweitert Schnittstelle

interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

Typalias erweitert Typalias

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

Die Schnittstelle erweitert den Typalias

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

Der Typ-Alias ​​erweitert die Schnittstelle

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. Geräte

Eine Klasse kann eine Schnittstelle oder einen Typalias auf dieselbe Weise implementieren. Beachten Sie jedoch, dass eine Klasse und eine Schnittstelle als statische Blaupausen betrachtet werden. Daher können sie keinen Typalias implementieren / erweitern, der einen Vereinigungstyp benennt.

interface Point {
  x: number;
  y: number;
}

class SomePoint implements Point {
  x = 1;
  y = 2;
}

type Point2 = {
  x: number;
  y: number;
};

class SomePoint2 implements Point2 {
  x = 1;
  y = 2;
}

type PartialPoint = { x: number; } | { y: number; };

// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}

5. Zusammenführung der Erklärung

Im Gegensatz zu einem Typalias kann eine Schnittstelle mehrfach definiert werden und wird als eine einzige Schnittstelle behandelt (wobei Mitglieder aller Deklarationen zusammengeführt werden).

// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };
Jabacchetta
quelle
9
Wenn die offiziellen Unterlagen veraltet sind, wo können die von Ihnen angegebenen Informationen bestätigt werden?
iX3
59
Basierend auf diesem Beitrag scheint der einzige Grund, eine Schnittstelle anstelle eines Typalias auszuwählen , darin zu bestehen, dass Sie die Funktion zum Zusammenführen von Deklarationen (Punkt 5) von Schnittstellen verwenden möchten. Darüber hinaus sind sie gleichwertig (und ich würde argumentieren, dass Typ-Aliase eine präzisere Syntax bieten).
Maxedison
17
Ich verwende immer Schnittstellen für das Objekttyp-Literal, andernfalls ist die Verwendung von Typen sinnvoller. Außerdem denke ich, dass das Zusammenführen von Deklarationen sowieso nicht verwendet werden sollte. Eigentlich werde ich nie erwarten, dass eine Schnittstelle in einer anderen Datei des Projekts mit einigen deklariert wird Zusätzliche Eigenschaften, die Typprüfung wurde ursprünglich durchgeführt, um Ihnen das Leben zu erleichtern und es mit diesen ninja-ähnlichen Schnittstellen nicht schwieriger zu machen: D
Ahmed Kamal
8
Im Grunde ist es also "fast eine persönliche" Wahl für das, was wir wirklich gerne benutzen? Abgesehen von einem Grund können Sie einfach verwenden typeoder interface? Ich bin immer noch verwirrt, wann ich das eine oder andere verwenden soll.
Joseph Briggs
7
Könnte jemand bitte eine Motivation dafür liefern, warum Sie das Zusammenführen von Schnittstellen wünschen? Das scheint mir möglicherweise verwirrend. Warum sollten Sie die Definition Ihrer Schnittstelle auf verschiedene Blöcke verteilen wollen?
Vanquish46
95

Ab TypeScript 3.2 (November 2018) gilt Folgendes:

Geben Sie hier die Bildbeschreibung ein

Karol Majewski
quelle
9
Könnten Sie bitte weitere Informationen darüber geben, wie die von Ihnen bereitgestellte Tabelle / das Bild generiert wurde? zB Quellcode oder Links zur Dokumentation
iX3
23
Ja, ich meinte die Quelle des Inhalts, nicht seine Präsentation.
iX3
3
Ich glaube nicht , eine Klasse kann erweitern entweder eine Art oder eine Schnittstelle, und ich kann nicht wirklich sehen , warum Sie wollen würde ??
Dan King
7
Vermeiden Sie das Posten von Textbildern, sondern fügen Sie stattdessen den eigentlichen Text direkt in Ihren Beitrag ein. Textbilder sind nicht leicht zu analysieren oder zu durchsuchen und für sehbehinderte Benutzer nicht zugänglich.
Andrew Marshall
2
Dieser Tabelle fehlen Quellen, um ihren Inhalt zu unterstützen, und ich würde mich nicht darauf verlassen. Beispielsweise können Sie rekursive Typen typemit bestimmten Einschränkungen definieren (und ab TypeScript 3.7 sind diese Einschränkungen ebenfalls weg). Schnittstellen können Typen erweitern. Klassen können Typen implementieren. Darüber hinaus ist die Darstellung von Daten als Screenshot einer Tabelle für Personen mit Sehbehinderung völlig unzugänglich.
Michał Miszczyszyn
5

Beispiele mit Typen:

// eine Baumstruktur für ein Objekt erstellen. Mit der Schnittstelle können Sie nicht dasselbe tun, da keine Schnittmenge (&) vorhanden ist.

type Tree<T> = T & { parent: Tree<T> };

// Typ, um eine Variable so einzuschränken, dass nur wenige Werte zugewiesen werden. Schnittstellen haben keine Union (|)

type Choise = "A" | "B" | "C";

// Dank der Typen können Sie dank eines bedingten Mechanismus den NonNullable-Typ deklarieren.

type NonNullable<T> = T extends null | undefined ? never : T;

Beispiele mit Schnittstelle:

// Sie können die Schnittstelle für OOP verwenden und 'implementiert' verwenden, um das Objekt- / Klassenskelett zu definieren

interface IUser {
    user: string;
    password: string;
    login: (user: string, password: string) => boolean;
}

class User implements IUser {
    user = "user1"
    password = "password1"

    login(user: string, password: string) {
        return (user == user && password == password)
    }
}

// Sie können Schnittstellen mit anderen Schnittstellen erweitern

    interface IMyObject {
        label: string,
    }

    interface IMyObjectWithSize extends IMyObject{
        size?: number
    }
Przemek Struciński
quelle
-2

Die Dokumentation hat erklärt

  • Ein Unterschied besteht darin, dass Schnittstellen einen neuen Namen erstellen, der überall verwendet wird. Typ-Aliase erstellen keinen neuen Namen. Beispielsweise verwenden Fehlermeldungen nicht den Aliasnamen. In älteren Versionen von TypeScript konnten Typ-Aliase nicht erweitert oder implementiert werden (und sie konnten auch keine anderen Typen erweitern / implementieren). Ab Version 2.7 können Typaliasnamen durch Erstellen eines neuen Schnittpunkttyps erweitert werden
  • Wenn Sie jedoch mit einer Schnittstelle keine Form ausdrücken können und einen Union- oder Tupeltyp verwenden müssen, sind normalerweise Typaliasnamen der richtige Weg.

Schnittstellen vs. Typ-Aliase

Liu Lei
quelle