ProgrammierungTypeScript-Architekt

Wie wird Pattern Matching in TypeScript über diskriminierte Vereinigungen implementiert? Wie strukturiert man die Typen richtig und welche Fallstricke gibt es?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

In TypeScript wird Pattern Matching über "diskriminierte Vereinigungen" implementiert. Jeder Objekt in der Vereinigung erhält ein erforderliches Diskriminatorfeld (in der Regel eine Zeichenkette, zum Beispiel type), anhand dessen TypeScript die Varianten unterscheidet.

Beispiel:

type Success = { type: 'success'; data: string }; type Failure = { type: 'failure'; error: string }; type Result = Success | Failure; function handleResult(result: Result) { switch (result.type) { case 'success': // result: Success console.log(result.data); break; case 'failure': // result: Failure console.error(result.error); break; } }

In switch/case oder if wird TypeScript den Typ mithilfe des Diskriminatorfeldes genau auf die benötigte Variante einschränken.

Hauptvorteile:

  • Strenge Typisierung – man kann nicht auf nicht existierende Felder zugreifen.
  • Exhaustiveness-Prüfung – wenn nicht alle Varianten behandelt werden, tritt manchmal ein Fehler auf (kann explizit erzwungen werden).

Fangfrage

Wenn man eine neue Variante zur diskriminierten Vereinigung hinzufügt, wird TypeScript dann zwingend verlangen, dass alle switch-case-Anweisungen aktualisiert werden, um die neue Variante zu behandeln?

Antwort: Nein, nur wenn man explizit die Behandlung einer "unmöglichen" Variante hinzufügt. Zum Beispiel durch die Verwendung der never-Funktion:

Beispiel:

function assertNever(x: never): never { throw new Error('Unerwartete Variante: ' + x); } function handle(r: Result) { switch(r.type) { case 'success': /* ... */; break; case 'failure': /* ... */; break; default: return assertNever(r); // TS gibt einen Fehler aus, wenn ein neuer Typ erscheint } }

Beispiele für reale Fehler aufgrund mangelnden Wissens über die Feinheiten des Themas.


Geschichte

Nach der Erweiterung des Typs "Result" um eine neue Variante ('pending') wurden in mehreren Stellen der Anwendung die alten switch-case-Anweisungen nicht aktualisiert, um diesen Fall zu behandeln. In der Folge hörten einige Schnittstellen auf zu funktionieren. Der Fehler wurde erst in der Produktion eine Woche nach der Veröffentlichung bemerkt.


Geschichte

Der Versuch, diskriminierte Vereinigungen ohne eindeutigen Diskriminator zu verwenden (das type-Feld wurde in zwei Typen dupliziert), führte zu einer "Verschlierung" der Typen: TypeScript hörte auf, den Typ genau einzuschränken und es wurde möglich, auf nicht existierende Felder ohne Kompilierungsfehler zuzugreifen. Mehrere kritische Bugs wurden in die Produktion überführt.


Geschichte

In einem Projekt wurde Pattern Matching durch if-else über mehrere Felder implementiert, anstatt einen expliziten Diskriminator zu verwenden. Dies erschwerte den Übergang zur Exhaustiveness-Prüfung mit der never-Funktion und verschlechterte die Lesbarkeit des Codes – die switch-case-Anweisungen funktionierten nicht korrekt und neue Varianten "zerstörten" die bestehende Logik.