Zustände eines Auftrags
Eine diskriminierte Union ist nicht nur für verschiedene Arten von Dingen gut, sondern auch für die verschiedenen Zustände einer einzigen Sache. Ein Auftrag in Kiras Auftragsbuch kann offen, erledigt oder gescheitert sein, und jeder Zustand hat eigene Daten: Ein erledigter Auftrag hat eine Belohnung, ein gescheiterter den Grund, warum er gescheitert ist, und ein offener hat keins von beiden:
type Auftrag =
| { status: "offen"; titel: string }
| { status: "erledigt"; titel: string; belohnung: number }
| { status: "gescheitert"; titel: string; grund: string };Der Tag heißt hier status, weil er das beschreibt. Der Name bleibt dir überlassen; es muss nur in jedem Glied der Union dieselbe Eigenschaft sein, mit je einem anderen Literaltyp. Eine so lange Union liest sich leichter auf mehreren Zeilen. Dann kannst du vor jedes Glied ein | schreiben, auch vor das erste: TypeScript ignoriert einen Strich ganz am Anfang.
Der Typ sagt genau, was du über jeden Auftrag weißt. Nur ein erledigter Auftrag hat eine Belohnung, das Lesen von auftrag.belohnung ohne Prüfung ist also ein Fehler:
type Auftrag =
| { status: "offen"; titel: string }
| { status: "erledigt"; titel: string; belohnung: number }
| { status: "gescheitert"; titel: string; grund: string };
const auftraege: Auftrag[] = [
{ status: "erledigt", titel: "Wölfe im Wald", belohnung: 50 },
{ status: "offen", titel: "Die verlorene Krone" },
{ status: "gescheitert", titel: "Rette den Müller", grund: "die Mühle brannte nieder" },
];
for (const auftrag of auftraege) {
console.log(`${auftrag.titel}: ${auftrag.belohnung} Gold`);
}main.ts(13,46): error TS2339: Property 'belohnung' does not exist on type 'Auftrag'.
Property 'belohnung' does not exist on type '{ status: "offen"; titel: string; }'.Die zweite Zeile der Meldung sagt sogar, welcher Auftrag keine Belohnung hat: der offene. Und ein Auftrag, der keinen Sinn ergibt, lässt sich gar nicht schreiben: const verloreneKrone: Auftrag = { status: "offen", titel: "Die verlorene Krone", belohnung: 100 }; ergibt error TS2353: Object literal may only specify known properties, and 'belohnung' does not exist in type '{ status: "offen"; titel: string; }'.
Die Eigenschaft titel steht in allen drei Gliedern, du kannst sie also bei jedem Auftrag lesen. Prüfe für den Rest zuerst den Status:
for (const auftrag of auftraege) {
if (auftrag.status === "erledigt") {
console.log(`${auftrag.titel}: ${auftrag.belohnung} Gold`);
} else {
console.log(`${auftrag.titel}: keine Belohnung`);
}
}Das gibt aus:
Wölfe im Wald: 50 Gold
Die verlorene Krone: keine Belohnung
Rette den Müller: keine BelohnungVergleiche das mit einem einzigen Typ mit optionalen Eigenschaften, { status: string; titel: string; belohnung?: number; grund?: string }. Er erlaubt einen offenen Auftrag mit Belohnung, einen erledigten ohne und sogar den Status "erldigt". Die nächste Übung handelt von solchen Typen.
So schreibst du es:
Anweisungen
- 1
Führe das Programm aus: Der dritte Auftrag passt nicht zum Typ. Füge der Union
Auftragein drittes Glied hinzu: einen gescheiterten Auftrag mitstatus: "gescheitert", einemtitelund einemgrund(beide Texte). - 2
Schreibe eine Funktion
beschreibeAuftragmit einem Parameterauftragvom TypAuftrag, die eine Beschreibung des Auftrags zurückgibt. Verwendeswitchaufauftrag.status(zur Übung mit einer Vollständigkeitsprüfung indefault) und gib die Beschreibung jedes Auftrags aus. Das Programm gibt dann aus:Wölfe im Wald: erledigt, +50 Gold Die verlorene Krone: offen Rette den Müller: gescheitert (die Mühle brannte nieder) Die Goblinbrücke: erledigt, +30 Gold - 3
Addiere die Belohnungen der erledigten Aufträge und gib die Summe am Ende aus:
Wölfe im Wald: erledigt, +50 Gold Die verlorene Krone: offen Rette den Müller: gescheitert (die Mühle brannte nieder) Die Goblinbrücke: erledigt, +30 Gold Gesamtbelohnung: 80 Gold