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:
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 } }
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.