Literal-Unions
Viele Werte in einem Spiel stammen aus einer kurzen, festen Liste. Ein Held ist ein Krieger, ein Magier oder ein Waldläufer; auf der Karte gehst du nach Norden, Süden, Osten oder Westen. Als Text ist ein solcher Wert ein string, aber ein string kann jeder beliebige Text sein, Tippfehler eingeschlossen:
function startleben(klasse: string): number {
if (klasse === "Krieger") {
return 120;
} else if (klasse === "Magier") {
return 70;
} else {
return 90;
}
}
console.log(startleben("Kriegre"));Das gibt 90 aus, das Leben eines Waldläufers, weil "Kriegre" nicht "Krieger" ist. Es gibt keinen Fehler, nur eine falsche Zahl irgendwo im Spiel, und du suchst vielleicht lange nach der Ursache.
In der Lektion über Basistypen hast du gesehen, dass ein Literaltyp wie "schwer" genau einen Wert erlaubt. Mit | kannst du mehrere Literaltypen zu einer Literal-Union verbinden und ihr mit type einen Namen geben:
type HeldenKlasse = "Krieger" | "Magier" | "Waldläufer";Eine HeldenKlasse ist einer dieser drei Texte und sonst nichts. Setze diese Zeile an den Anfang des Programms oben, ändere den Parameter in klasse: HeldenKlasse, und TypeScript prüft jeden Aufruf:
main.ts(13,24): error TS2345: Argument of type '"Kriegre"' is not assignable to parameter of type 'HeldenKlasse'.Die Anführungszeichen in den Anführungszeichen bedeuten genau den Text "Kriegre", wie du es von Literaltypen kennst. Derselbe Schutz gilt überall, wo der Typ verwendet wird. Bei einer Variablen schlägt TypeScript sogar vor, was du wahrscheinlich gemeint hast:
type HeldenKlasse = "Krieger" | "Magier" | "Waldläufer";
let gewaehlt: HeldenKlasse = "Kriegre";main.ts(3,5): error TS2820: Type '"Kriegre"' is not assignable to type 'HeldenKlasse'. Did you mean '"Krieger"'?Und es prüft auch Vergleiche. Stünde der Tippfehler in der Funktion, in if (klasse === "Kriegre"), würde TypeScript melden:
main.ts(4,9): error TS2367: This comparison appears to be unintentional because the types 'HeldenKlasse' and '"Kriegre"' have no overlap.„No overlap“ bedeutet, dass kein Wert zugleich eine HeldenKlasse und der Text "Kriegre" ist, der Vergleich also nie wahr sein könnte.
Eine Sache überrascht dich vielleicht. Wenn die Klasse in einer let-Variablen ohne Typ steht, ist der Aufruf ein Fehler, obwohl "Magier" eine Klasse ist. Mit diesen zwei Zeilen unter der Funktion:
let wahl = "Magier";
console.log(startleben(wahl));main.ts(14,24): error TS2345: Argument of type 'string' is not assignable to parameter of type 'HeldenKlasse'.TypeScript hat für wahl den Typ string abgeleitet, wie bei jedem let mit einem Text: Später könntest du jeden anderen Text darin speichern. Gib der Variablen entweder den Typ, let wahl: HeldenKlasse = "Magier";, oder verwende const: Der Typ von const wahl = "Magier" ist der Literaltyp "Magier", und der passt.
Ein Hinweis für später: In anderen Sprachen und in älterem TypeScript-Code siehst du solche Listen vielleicht als enum geschrieben, zum Beispiel enum Richtung { Norden, Sueden }. Anders als andere Typen verschwindet ein Enum nicht einfach, wenn die Typen entfernt werden: Es wird zu eigenem JavaScript-Code. Deshalb erlauben die Einstellungen dieser Seite es nicht:
main.ts(1,6): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.Neuerer TypeScript-Code verwendet oft stattdessen Literal-Unions, und du wirst das auch tun.
So schreibst du es:
Anweisungen
- 1
Das Programm gibt dreimal
90aus, aber ein Krieger soll mit 120 Leben starten und ein Magier mit 70. Erstelle über der Funktion den TypHeldenKlassefür die drei Klassen"Krieger","Magier"und"Waldläufer"und mache ihn zum Typ des Parametersklasse. TypeScript findet dann zwei Tippfehler: Behebe sie, sodass das Programm ausgibt:120 70 90 - 2
Erstelle unter den Aufrufen einen Typ
Heldfür ein Objekt mit einemname(ein Text) und einerklassevom TypHeldenKlasse. Erstelle dannkiravom TypHeld: Ihr Name ist"Kira", und sie ist eine"Waldläufer". - 3
Gib eine Zeile über Kira aus, mit ihren Eigenschaften und
startleben. Das Programm gibt dann aus:120 70 90 Kira (Waldläufer) startet mit 90 Leben