Modelliere die Zustände deiner Anwendung mit Unions, die der Compiler für dich prüft.
Diese Lektion in Kodokon öffnenEin Literaltyp schränkt einen Wert auf einen exakten Inhalt ein: 'info' statt string. Das ist die Grundlage für APIs, die man kaum falsch verwenden kann: Der Compiler weist jeden Wert außerhalb der Liste zurück, und dein Editor bietet dir Autovervollständigung an.
type Level = "info" | "warn" | "error";
function log(level: Level, message: string): void {
console.log(`[${level}] ${message}`);
}
log("info", "Server started");
// log("fatal", "Boom"); -> rejected by the compilerDer nächste Schritt: Objekttypen kombinieren, die eine gemeinsame Literal-Eigenschaft teilen, den sogenannten Diskriminanten. Jeder Zustand eines Netzwerkaufrufs trägt zum Beispiel nur die Daten, die zu ihm gehören: Auf data zuzugreifen, während geladen wird, ist schlicht unmöglich.
type ApiState =
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };
function render(state: ApiState): string {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return state.data.join(", ");
case "error":
return state.message;
}
}In jedem case verengt TypeScript den Typ: Nach case 'error' existiert state.message, state.data dagegen nicht. Dieser Mechanismus, Narrowing genannt, ersetzt fragile manuelle Prüfungen. Ergänze eine Vollständigkeitsprüfung, um das Ganze abzusichern.
function assertNever(value: never): never {
throw new Error("Unhandled case: " + String(value));
}
function label(state: ApiState): string {
switch (state.status) {
case "loading": return "In progress";
case "success": return "Done";
case "error": return "Failed";
default: return assertNever(state);
}
}