Ein Ergebnistyp
Manche Funktionen können scheitern. Das Kaufen in einem Laden scheitert, wenn der Laden den Gegenstand nicht hat oder wenn der Held ihn sich nicht leisten kann. Eine Funktion könnte bei einem Fehlschlag undefined zurückgeben, aber dann weiß der Aufrufer nicht, warum. Kombiniere, was du kennst, eine diskriminierte Union (die Lektion Daten modellieren) und einen Typparameter, und du bekommst einen Typ für das Ergebnis von allem, was scheitern kann:
type Ergebnis<T> = { ok: true; wert: T } | { ok: false; fehler: string };Ein Ergebnis<T> ist entweder ein Erfolg mit einem wert vom Typ T oder ein Fehlschlag mit einer Fehlermeldung, fehler. Der Tag ist ok. Seine Typen sind die Literaltypen true und false: Wie "trank" erlaubt jeder nur diesen einen Wert. Ein Typ genügt für alle Funktionen, die scheitern können: Ergebnis<number>, Ergebnis<Held> und so weiter.
type Ergebnis<T> = { ok: true; wert: T } | { ok: false; fehler: string };
function teileGold(gold: number, helden: number): Ergebnis<number> {
if (helden === 0) {
return { ok: false, fehler: "niemand zum Teilen da" };
}
return { ok: true, wert: gold / helden };
}
const anteil = teileGold(120, 3);
if (anteil.ok) {
console.log(`Jeder Held bekommt ${anteil.wert} Gold`);
} else {
console.log(`Teilen nicht möglich: ${anteil.fehler}`);
}Das gibt aus:
Jeder Held bekommt 40 GoldInnerhalb von if (anteil.ok) weiß TypeScript, dass es ein Erfolg ist, also ist anteil.wert eine Zahl. Im else-Zweig ist es ein Fehlschlag, und der hat einen fehler. Vor der Prüfung könnte anteil beides sein, also ist die Verwendung von wert ein Fehler. Füge am Ende console.log(teileGold(120, 0).wert); hinzu, und TypeScript meldet:
main.ts(16,31): error TS2339: Property 'wert' does not exist on type 'Ergebnis<number>'.
Property 'wert' does not exist on type '{ ok: false; fehler: string; }'.Die zweite Zeile erklärt es: Ein Fehlschlag hat keinen wert. Das ist der Sinn von Ergebnis: Wie beim undefined von find zwingt TypeScript jeden Aufrufer, beide Fälle zu behandeln, sodass ein Fehlschlag nicht vergessen werden kann. Und anders als undefined sagt ein Fehlschlag auch, was schiefgegangen ist. Viele TypeScript-Programme verwenden dieses Muster.
Typische Fehler:
- Die beiden Fälle vermischen:
return { ok: true, fehler: "…" };ergibtObject literal may only specify known properties, and 'fehler' does not exist in type '{ ok: true; wert: number; }'.(TS2353). ok: "true"(ein Text) stattok: trueschreiben.- Das Typargument weglassen:
Ergebnisallein ergibt TS2314,Generic type 'Ergebnis' requires 1 type argument(s).
So schreibst du es:
Anweisungen
- 1
Deklariere unter dem Laden den Typ
Ergebnis<T>genau wie oben:{ ok: true; wert: T }oder{ ok: false; fehler: string }. - 2
Schreibe eine Funktion
kaufe(laden: Gegenstand[], name: string, gold: number): Ergebnis<Gegenstand>. Sie findet den Gegenstand mitfindüber seinen Namen. Wenn der Laden ihn nicht hat, scheitert sie mit dem Fehler`kein ${name} im Laden`. Wenn der Gegenstand mehr alsgoldkostet, scheitert sie mit dem Fehler`nicht genug Gold für ${name}`. Sonst ist sie erfolgreich, mit dem Gegenstand als Wert. - 3
Kira hat 50 Gold und versucht, drei Dinge zu kaufen. Füge diese Schleife am Ende des Programms hinzu:
for (const name of ["Heiltrank", "Silberschwert", "Drachenei"]) { const ergebnis = kaufe(laden, name, 50); if (ergebnis.ok) { console.log(`Gekauft: ${ergebnis.wert.name}`); } else { console.log(`Fehlgeschlagen: ${ergebnis.fehler}`); } }Das Programm gibt aus:
Gekauft: Heiltrank Fehlgeschlagen: nicht genug Gold für Silberschwert Fehlgeschlagen: kein Drachenei im Laden