0 Tage Serie
javascript / expert
Snippet

Erschöpfende Union-Einschränkung für reaktive Formularzustände

Verwendet eine diskriminierte Union, um jeden erreichbaren Zustand des Formular-Übermittlungslebenszyklus abzubilden, und nutzt dann TypeScripts Kontrollfluss-Einschränkung innerhalb eines switch-Statements, um die Zusatzfelder jeder Verzweigung (recordId, message, retryable) ohne Typumwandlung verfügbar zu machen. Der assertNever-Helfer macht einen unbehandelten Fall sowohl zu einem Kompilierzeitfehler, falls später eine neue Zustandsvariante hinzukommt, als auch zu einer Laufzeitabsicherung.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type FormState =
| { status: 'idle' }
| { status: 'submitting' }
| { status: 'success'; recordId: string }
| { status: 'error'; message: string; retryable: boolean };
function assertNever(value: never): never {
throw new Error(`Unhandled form state: ${JSON.stringify(value)}`);
}
function describeState(state: FormState): string {
switch (state.status) {
case 'idle':
return 'Ready to submit';
case 'submitting':
return 'Submitting…';
case 'success':
return `Saved as ${state.recordId}`;
case 'error':
return state.retryable ? `Retry: ${state.message}` : `Failed: ${state.message}`;
default:
return assertNever(state);
}
}
angular
Erklärung
1
function assertNever(value: never): never
Akzeptiert ausschließlich den Typ `never` — wird also eine neue FormState-Variante ohne passenden case hinzugefügt, markiert TypeScript den Aufruf im default-Zweig als Typfehler.
2
case 'error':\n return state.retryable ? ... : ...;
Innerhalb dieses Falls schränkt TypeScript `state` gezielt auf die error-Variante ein, sodass `retryable` und `message` ohne optionale Verkettung zugänglich sind.
3
default:\n return assertNever(state);
Die Vollständigkeitsprüfung — nur erreichbar, wenn ein status-Wert durchrutscht, den kein case behandelt; dann wird mit der problematischen Nutzlast eine Ausnahme geworfen.