TypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler
Schnittstellen und Typaliase überschneiden sich so stark, dass die Auswahl oft willkürlich wirkt. Hier erfahren Sie, was jeder tun kann, was der andere nicht kann, was durch echte Compilerfehler bestätigt wird, sowie eine einfache Regel, die Ihr Team befolgen kann.
- Für einfache Objektformen sind eine Schnittstelle und ein Typ-Alias nahezu austauschbar.
- Nur
typekann Unions, Tupel und andere Nicht-Objekttypen benennen. - Nur
interfaceunterstützt die Deklarationszusammenführung, bei der zwei Deklarationen kombiniert werden. - Eine allgemeine Regel: Schnittstellen für Objektformen,
typefür alles andere, konsequent angewendet.
Nur wenige TypeScript-Fragen sorgen für so viele Debatten wie TypeScript-Schnittstelle vs. Typ. In vielen Artikeln werden Unterschiede aufgeführt, die in älteren Versionen eine Rolle spielten, jetzt aber veraltet sind. Anstatt also Behauptungen zu wiederholen, haben wir sie getestet.
Wir haben eine Datei geschrieben, die jeden Unterschied ausübt, und sie mit TypeScript 5.6.3 im strikten Modus überprüft. Die unten aufgeführten Compilerfehler stammen aus diesem Lauf. Das Verhalten kann sich zwischen den Versionen ändern. Vergleichen Sie es daher mit der TypeScript-Version, die Ihr Projekt verwendet. Wenn Sie neu in der Sprache sind, beginnen Sie mit unserem TypeScript-Tutorial für Anfänger.
Die kurze Antwort
Eine interface beschreibt die Form eines Objekts und kann erweitert oder erneut geöffnet werden. Ein type-Alias gibt einem jedem Typ einen Namen, einschließlich Objekten, Unions, Tupeln und Funktionstypen. Wo beides funktionieren kann, liegt der Unterschied hauptsächlich im Stil.
Wo sie gleich sind
Diese beiden Deklarationen beschreiben identische Formen:
interface User {
id: number;
name: string;
email?: string;
}
type UserAlias = {
id: number;
name: string;
email?: string;
};
const a: User = { id: 1, name: "Asha" };
const b: UserAlias = a; // no error
TypeScript verwendet strukturelle Typisierung, was bedeutet, dass es Formen statt Namen vergleicht. Deshalb kann eine User ohne Beanstandung einer UserAlias zugeordnet werden. Beide unterstützen optionale Eigenschaften, readonly Eigenschaften, Methoden und Indexsignaturen.
Schnittstelle vs. Typ nebeneinander
| Funktion | Schnittstelle | Typ |
|---|---|---|
| Objektformen | Ja | Ja |
Gewerkschaften wie "a" | "b" |
Nein | Ja |
| Tupel und Grundelemente | Nein | Ja |
| Zugeordnete und bedingte Typen | Nein | Ja |
| Deklarationszusammenführung | Ja | Nein, es ist ein Fehler |
| Erweitern | erstreckt sich |
& Kreuzung |
| Widersprüchliche Eigenschaften | Fehler bei der Deklaration | Kann ruhig zu never werden |
Verwendet mit implements |
Ja | Ja, wenn es sich um einen Objekttyp handelt |
Was nur Typ kann
Viele nützliche Typen sind überhaupt keine Objektformen und können nur mit einem Typalias benannt werden:
type Status = "pending" | "paid" | "shipped"; // union
type Point = [number, number]; // tuple
type Handler = (event: string) => void; // function type
type Keys = keyof User; // computed type
type ReadonlyUser = Readonly<User>; // utility type
Union-Typen gehören zu den wertvollsten Funktionen von TypeScript, da der Compiler dann jeden Wert außerhalb der Liste ablehnt:
let s: Status = "paid";
s = "refunded";
// error TS2322: Type '"refunded"' is not assignable to type 'Status'.
Dadurch werden Tippfehler und veraltete Werte zur Kompilierungszeit erkannt, bevor sie in die Produktion gelangen.
Deklarationszusammenführung
Wenn Sie eine Schnittstelle mit demselben Namen zweimal deklarieren, führt TypeScript sie zu einer zusammen:
interface Settings {
theme: string;
}
interface Settings {
language: string;
}
const settings: Settings = { theme: "dark", language: "en" }; // no error
Versuchen Sie dasselbe mit einem Typalias, aber der Compiler weigert sich:
type Config = { theme: string };
type Config = { language: string };
// error TS2300: Duplicate identifier 'Config'.
Durch das Zusammenführen können Sie mit Bibliotheken ihre Typen erweitern. Beispielsweise können Sie eine benutzerdefinierte Eigenschaft zur globalen Window-Schnittstelle oder zum Anforderungsobjekt eines Frameworks hinzufügen, ohne die Bibliothek zu ändern. Das ist wirklich nützlich.
Die Kehrseite ist, dass eine Zusammenführung zufällig erfolgen kann. Wenn zwei Dateien in einem Projekt eine Schnittstelle mit demselben Namen im selben Bereich deklarieren, werden sie stillschweigend kombiniert, was verwirrend sein kann. Ein Typalias macht diese Kollision stattdessen zu einem Fehler.
erstreckt sich vs. Kreuzungen
Mit beiden können Sie auf einem vorhandenen Typ aufbauen:
interface Admin extends User {
permissions: string[];
}
type AdminAlias = UserAlias & { permissions: string[] };
Bei kompatiblen Eigenschaften ist das Ergebnis dasselbe. Der Unterschied zeigt sich in einem Konflikt. Wenn eine Schnittstelle versucht, den Typ einer Eigenschaft inkompatibel zu ändern, meldet der Compiler dies sofort:
interface Base { id: number }
interface Broken extends Base { id: string }
// error TS2430: Interface 'Broken' incorrectly extends interface 'Base'.
// Types of property 'id' are incompatible.
// Type 'string' is not assignable to type 'number'.
Eine Kreuzung beschwert sich nicht, wenn sie deklariert wird. Stattdessen wird die widersprüchliche Eigenschaft zu never, einem Typ, den kein Wert haben kann. Der Fehler tritt erst später auf, wenn Sie versuchen, ihn zu verwenden:
type Mixed = { id: number } & { id: string };
const m: Mixed = { id: 1 };
// error TS2322: Type 'number' is not assignable to type 'never'.
Dieser spätere Fehler ist verwirrender, da er vom eigentlichen Fehler abweicht. Dies ist ein praktischer Grund, extends beim Aufbau von Objekttypen zu bevorzugen.
Klassen und Implementierungen
Eine Klasse kann mithilfe von implements versprechen, einer Form zu entsprechen, und dies funktioniert mit einer Schnittstelle oder einem Objekttyp-Alias:
class Account implements User {
constructor(public id: number, public name: string) {}
}
Dies wurde ohne Fehler kompiliert. Beachten Sie, dass implements nur prüft, ob die Klasse übereinstimmt. Es werden keine Eigenschaften oder Code hinzugefügt. Eine Klasse kann keinen Union-Typ implementieren, da es keine einzelne passende Form gibt.
Schreibgeschützte und Dienstprogrammtypen
Dienstprogrammtypen wie Readonly, Partial, Pick und Omit funktionieren sowohl mit Schnittstellen als auch mit Aliasen. Das Ergebnis ist ein neuer Typ, der normalerweise mit einem Typalias benannt wird:
const r: ReadonlyUser = { id: 3, name: "Dev" };
r.name = "Chitra";
// error TS2540: Cannot assign to 'name' because it is a read-only property.
Denken Sie daran, dass readonly nur eine Überprüfung zur Kompilierungszeit ist. Zur Laufzeit handelt es sich bei dem Objekt um normales JavaScript und es kann dennoch durch Code geändert werden, der die Typen umgeht.
Tipp: Typen verschwinden, wenn TypeScript zu JavaScript kompiliert wird. Daten, die von außen eintreffen, beispielsweise eine API-Antwort, werden zur Laufzeit nicht überprüft, nur weil sie einen Typ haben. Validieren Sie es, beispielsweise mit einer Schemabibliothek. Unser Tutorial zum Abrufen der API behandelt den sicheren Umgang mit API-Antworten.
Compiler-Leistung
Die eigenen Leistungsrichtlinien des TypeScript-Teams schlagen vor, Schnittstellen, die extends verwenden, gegenüber großen Schnittmengen zu bevorzugen, da der Compiler Schnittstellenbeziehungen effizienter zwischenspeichern kann. Bei kleinen und mittleren Projekten werden Sie wahrscheinlich keinen Unterschied bemerken. Dies kann in sehr großen Codebasen mit tief zusammengesetzten Typen von Bedeutung sein. Wir haben dies nicht selbst gemessen.
Welches sollten Sie verwenden?
Eine weit verbreitete Regel, die den Leitlinien des TypeScript-Handbuchs entspricht, lautet:
- Verwenden Sie
interfacefür Objektformen, insbesondere öffentliche APIs und alles, was Klassen implementieren oder andere erweitern können. - Verwenden Sie
typefür Vereinigungen, Tupel, Funktionstypen und zugeordnete oder berechnete Typen.
| Du definierst | Benutzen |
|---|---|
| Ein Datenmodell, z. B. Benutzer oder Bestellung | Schnittstelle |
| Eine Reihe zulässiger Werte | type Gewerkschaft |
| Ein Paar oder Tripel mit fester Länge | type Tupel |
| Eine Rückrufsignatur | Typ |
| Erweitern der Typen einer Bibliothek | interface, durch Zusammenführung |
| Eine Variation eines vorhandenen Typs | type mit einem Dienstprogrammtyp |
Manche Teams verwenden einfach überall type, und das funktioniert auch gut. Am wichtigsten ist die Konsistenz. Wählen Sie also eine Konvention, schreiben Sie sie in Ihren Styleguide und lassen Sie sie von einem Linter durchsetzen. Die consistent-type-definitions-Regel von ESLint aus typescript-eslint kann dies tun.
Häufige Fehler
- Endlose Debatte. Beides ist für Objekte in Ordnung, also klären Sie die Regel einmal und machen Sie weiter.
- Versehentliches Zusammenführen. Die Wiederverwendung eines Schnittstellennamens im selben Bereich führt diese stillschweigend zusammen.
- Widersprüchliche Schnittmengen. Sie erstellen später
neverTypen mit verwirrenden Fehlern. - Typen zur Laufzeit vertrauen. Sie werden gelöscht, also validieren Sie externe Daten.
- Verwendung von
anyzum Stummschalten von Fehlern. Die Überprüfung wird ausgeschaltet. Bevorzugen Sieunknownund grenzen Sie es ein.
Wechseln zwischen ihnen in einer vorhandenen Codebasis
Das Ändern einer interface in eine type oder umgekehrt ist für einfache Objektformen normalerweise sicher, da TypeScript Typen anhand ihrer Struktur und nicht anhand ihrer Namen vergleicht. Vor dem Wechsel müssen noch einige Dinge überprüft werden:
- Durch das Konvertieren einer Schnittstelle in einen Typalias wird die Deklarationszusammenführung aufgehoben, sodass jede zweite Deklaration mit demselben Namen zu einem Fehler wegen doppelter Bezeichner wird.
- Das Konvertieren eines Typalias in eine Schnittstelle funktioniert nur für Objektformen. Unions, Tupel und zugeordnete Typen müssen als Typaliase bleiben.
- Fehlermeldungen und Editor-Hover zeigen den Typ möglicherweise anders an, was Teamkollegen überraschen kann, aber das Verhalten nicht ändert.
Nehmen Sie die Änderung in einem fokussierten Pull-Request vor, führen Sie den Compiler im strikten Modus und Ihre Testsuite aus und vermeiden Sie eine Vermischung mit Feature-Arbeit, damit Prüfer sehen können, dass sich sonst nichts geändert hat.
Fazit
Auf die Frage zwischen Schnittstelle und Typ gibt es eine klare Antwort: Sie überschneiden sich bei Objekten, jedes hat ein paar einzigartige Fähigkeiten und Konsistenz ist wichtiger als die Auswahl. Verwenden Sie für alles andere Schnittstellen für Formen und Typen, sofern Ihr Team nichts anderes bevorzugt. Um die Unterschiede selbst zu sehen, kopieren Sie die obigen Beispiele in eine Datei und führen Sie tsc --noEmit --strict darauf aus.
Häufige Fragen
Was ist der Unterschied zwischen Schnittstelle und Typ in TypeScript?
Beide können Objektformen beschreiben. Nur der Typ kann Unions, Tupel und berechnete Typen benennen, während nur die Schnittstelle das Zusammenführen von Deklarationen unterstützt.
Sollte ich eine Schnittstelle oder einen Typ für React-Requisiten verwenden?
Beides funktioniert gut. Viele Teams verwenden Schnittstellen für Requisiten, während andere Schriftarten aus Gründen der Konsistenz mit Gewerkschaften bevorzugen. Wählen Sie eines aus und wenden Sie es im gesamten Projekt an.
Kann ein Typ eine Schnittstelle erweitern?
Ja, indem Sie eine Schnittmenge wie den Typ „Admin = Benutzer & { Berechtigungen: Zeichenfolge[]} verwenden. Eine Schnittstelle kann auch einen Objekttyp-Alias erweitern.
Ist die Schnittstelle schneller als der Typ?
Die Leistungsrichtlinien von TypeScript bevorzugen Schnittstellenerweiterungen über große Schnittmengen in großen Codebasen. Bei typischen Projekten dürfte der Unterschied kaum spürbar sein.
Was ist die Zusammenführung von Deklarationen?
Dies ist der Fall, wenn zwei Schnittstellen mit demselben Namen im selben Bereich zu einer kombiniert werden. Typaliase können nicht zusammengeführt werden und doppelte Namen verursachen einen Fehler.
Lerne weiter
Benötigen Sie Hilfe beim Testen, WordPress oder SEO?
Wir helfen Teams, bessere Software zu liefern und ihre Websites zu erweitern. Sagen Sie uns, woran Sie gerade arbeiten, und wir schlagen Ihnen einen klaren nächsten Schritt vor.
Weitere Anleitungen finden Sie unter Tests, KI und moderne Entwicklung
Hat Ihnen dieser Artikel gefallen? Wählen Sie ein Thema und springen Sie direkt in unsere neuesten Tutorials.
KI-Halluzinationen erklärt: Warum Sprachmodelle Dinge erfinden und wie man sie reduziert
KI-Halluzinationen erklärt: Was sie sind, warum Sprachmodelle sie produzieren, gängige Typen, wie man sie mit Erdung und Eingabeaufforderungen reduz…
Artikel lesen →DevOpsErklärte Umgebungsvariablen: .env-Dateien, Geheimnisse und Konfiguration richtig gemacht
Umgebungsvariablen anhand von Python-Beispielen erklärt, die wir ausgeführt haben: Sie lesen und festlegen, warum jeder Wert ein String ist, .env-Da…
Artikel lesen →SoftwareentwicklungAPI-Ratenbegrenzung erklärt: Algorithmen, Header und Behandlung von 429-Fehlern
API-Ratenbegrenzung anhand einer von uns durchgeführten Simulation erklärt: Token-Bucket, festes Fenster, gleitendes Fenster, 429 Antworten, Ratenbe…
Artikel lesen →TestautomatisierungSpott in Python: unittest.mock, Patch und die Fehler, die Tests zum Lügen machen
Mocking in Python mit unittest.mock, getestet: Mock und return_value, side_effect, Patchen, wo ein Name verwendet wird, Spezifikation und Autospec, …
Artikel lesen →SoftwaretestsCode-Abdeckung erklärt: Leitungs- und Zweigstellenabdeckung und was 100 % wirklich bedeutet
Erklärung der Codeabdeckung anhand eines echten Coverage.py-Laufs: Zeilen-, Zweig- und Bedingungsabdeckung, Lesen eines Berichts, warum bei 100 % Ab…
Artikel lesen →Datenbanken & SQLDELETE vs. TRUNCATE vs. DROP in SQL: Unterschiede, Rollback und Verwendungszweck
DELETE vs. TRUNCATE vs. DROP erklärt mit getestetem SQL: was jeweils entfernt wird, Rollback, Trigger, Identitätsrücksetzung, Geschwindigkeit und wi…
Artikel lesen →Datenbanken & SQLErklärte SQL-Ansichten: Erstellen, nutzen und vermeiden Sie Fallstricke mit Beispielen
SQL-Ansichten anhand der von uns ausgeführten Abfragen erklärt: Erstellen einer Ansicht, Live-Ergebnisse, Ausblenden von Spalten, Leistung, aktualis…
Artikel lesen →SoftwareentwicklungTypeScript-Schnittstelle vs. Typ: Echte Unterschiede, getestet mit dem Compiler
TypeScript-Schnittstelle vs. Typ, überprüft mit dem echten Compiler: Was beide können, was nur einer kann, Deklarationszusammenführung, Erweiterunge…
Artikel lesen →SoftwareentwicklungPython *args und **kwargs erklärt: Flexible Funktionen mit klaren Beispielen
Python *args und **kwargs erklärt mit Code, den wir ausgeführt haben: Packen und Entpacken, Parameterreihenfolge, Nur-Schlüsselwort- und Nur-Positio…
Artikel lesen →SoftwareentwicklungPython-Lambda-Funktionen: Syntax, tatsächliche Verwendung und wann man sie nicht verwendet
Python-Lambda-Funktionen erklärt mit Code, den wir ausgeführt haben: Syntax, Sortierung mit Schlüssel, Karte und Filter, Abschlüsse, die Late-Bindin…
Artikel lesen →Künstliche IntelligenzWas sind KI-Agenten? Wie sie funktionieren, mit einer einfachen Agentenschleife, die Sie ausführen können
Was sind KI-Agenten? Eine einfache Anleitung zur Agentenschleife, zu Tools, Speicher und Leitplanken, mit einer kleinen Python-Schleife, die wir aus…
Artikel lesen →DevOpsÜberwachung vs. Beobachtbarkeit: Der wahre Unterschied, mit Protokollen, Metriken und Traces
Überwachung vs. Beobachtbarkeit erklärt: bekannte und unbekannte Fehler, Protokolle, Metriken und Spuren, eine exemplarische Vorgehensweise für Chec…
Artikel lesen →DevOpsDocker-Volumes vs. Bind Mounts: Containerdaten auf die richtige Art und Weise beibehalten
Docker-Volumes vs. Bind-Mounts erklärt: Warum Containerdaten verschwinden, benannte Volumes, Bind-Mounts, tmpfs, Compose-Beispiele, Backups, Berecht…
Artikel lesen →TestautomatisierungTDD vs. BDD: Hauptunterschiede, eine Funktion, die auf beide Arten entwickelt wurde und wann sie jeweils verwendet werden sollte
TDD vs. BDD erklärt mit einer Rabattfunktion, die in beide Richtungen aufgebaut ist: Rot-Grün-Refaktor mit Code, den wir ausgeführt haben, Gegeben-W…
Artikel lesen →SoftwareentwicklungGit merge vs rebase: Unterschiede, Beispiele und wann man was nutzt
Git merge vs rebase erklärt mit echter Log-Ausgabe, einer Vergleichstabelle, der goldenen Regel des Rebase und einem sicheren Team-Workflow.
Artikel lesen →SoftwareentwicklungPython List Comprehension: Syntax, Beispiele und wann man darauf verzichtet
Python List Comprehension erklärt: Syntax, Filter, if-else, verschachtelte Schleifen, gemessene Zeiten und Fälle, in denen eine normale for-Schleife…
Artikel lesen →Datenbanken & SQLSQL Joins erklärt mit Beispielen (Inner, Left, Right, Full)
SQL Joins Schritt für Schritt mit Beispieltabellen und Abfragen verstehen: INNER, LEFT, RIGHT, FULL, CROSS und SELF, plus typische Fehler und Perfor…
Artikel lesen →