Kurz: Ein Wert kann einer von mehreren Typen sein:
Teil des Kurses TypeScript
Kapitel 5 von 15 im Kurs TypeScript. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.
Union-Typen
Ein Wert kann einer von mehreren Typen sein:
function formatiere(wert: string | number): string {
if (typeof wert === "string") {
return wert.toUpperCase(); // hier ist wert: string
}
return wert.toFixed(2); // hier ist wert: number
}
console.log(formatiere("hallo"), formatiere(3.14159));Ausgabe:
HALLO 3.14Innerhalb der if-Zweige verengt TypeScript den Typ (Narrowing). Das funktioniert mit:
| Prüfung | Verengt auf |
|---|---|
typeof x === "string" | string (auch number, boolean, function) |
x instanceof Date | Klasse |
Array.isArray(x) | Array |
"name" in x | Typ mit Eigenschaft name |
x !== null, x != null, if (x) | ohne null/undefined |
x === "a" | der Literaltyp |
function laenge(x: string | string[] | null): number {
if (x === null) return 0;
if (Array.isArray(x)) return x.length;
return x.length;
}
console.log(laenge(null), laenge(["a", "b"]), laenge("Hallo"));Ausgabe:
0 2 5Literaltypen
Typen können einzelne feste Werte sein:
type Richtung = "links" | "rechts" | "oben" | "unten";
type Wuerfel = 1 | 2 | 3 | 4 | 5 | 6;
function gehe(r: Richtung, schritte: number = 1): string {
return `${schritte} Schritt(e) nach ${r}`;
}
const w: Wuerfel = 4;
console.log(gehe("links"), gehe("oben", 3), w);Ausgabe:
1 Schritt(e) nach links 3 Schritt(e) nach oben 4type Richtung = "links" | "rechts";
function gehe(r: Richtung) {}
gehe("hinten");Fehlermeldung:
error TS2345: Argument of type '"hinten"' is not assignable to parameter of type 'Richtung'.Das ist viel sicherer als einfache Strings: Tippfehler fallen auf, und die Autovervollständigung zeigt alle erlaubten Werte.
Diskriminierte Unions
Das mächtigste Muster: Jede Variante hat ein gemeinsames Feld (Diskriminante), an dem sie erkannt wird:
type Form =
| { art: "kreis"; radius: number }
| { art: "rechteck"; breite: number; hoehe: number }
| { art: "dreieck"; basis: number; hoehe: number };
function flaeche(f: Form): number {
switch (f.art) {
case "kreis":
return Math.PI * f.radius ** 2;
case "rechteck":
return f.breite * f.hoehe;
case "dreieck":
return (f.basis * f.hoehe) / 2;
}
}
console.log(flaeche({ art: "kreis", radius: 1 }).toFixed(2));
console.log(flaeche({ art: "rechteck", breite: 3, hoehe: 4 }));
console.log(flaeche({ art: "dreieck", basis: 6, hoehe: 5 }));Ausgabe:
3.14
12
15In jedem case kennt TypeScript die passende Variante (f.radius gibt es nur beim Kreis).
Vollständigkeit prüfen mit never
Wenn du später eine neue Form ergänzt und einen case vergisst, soll der Compiler warnen:
function pruefe(x: never): never {
throw new Error("Nicht behandelt: " + JSON.stringify(x));
}
type Ampel = "rot" | "gelb" | "gruen";
function aktion(a: Ampel): string {
switch (a) {
case "rot": return "halt";
case "gelb": return "achtung";
case "gruen": return "los";
default: return pruefe(a); // Fehler, sobald ein Fall fehlt
}
}
console.log(aktion("rot"), aktion("gruen"));Ausgabe:
halt losEigene Typprüfer (Type Guards)
interface Hund { bellen(): string }
interface Katze { miauen(): string }
function istHund(t: Hund | Katze): t is Hund {
return "bellen" in t;
}
function laut(t: Hund | Katze): string {
return istHund(t) ? t.bellen() : t.miauen();
}
console.log(laut({ bellen: () => "Wuff" }), laut({ miauen: () => "Miau" }));Ausgabe:
Wuff Miaut is Hund sagt dem Compiler: Wenn die Funktion true liefert, ist t ein Hund.
Ergebnis oder Fehler
Mit diskriminierten Unions lässt sich Fehlerbehandlung ohne Ausnahmen abbilden:
type Ergebnis<T> = { ok: true; wert: T } | { ok: false; fehler: string };
function teile(a: number, b: number): Ergebnis<number> {
return b === 0 ? { ok: false, fehler: "Division durch 0" } : { ok: true, wert: a / b };
}
for (const [a, b] of [[10, 2], [1, 0]]) {
const r = teile(a, b);
console.log(r.ok ? `Ergebnis ${r.wert}` : `Fehler: ${r.fehler}`);
}Ausgabe:
Ergebnis 5
Fehler: Division durch 0Merke
A | B: Wert ist einer der Typen; innerhalb von Prüfungen wird der Typ eingeengt (Narrowing)- Literaltypen (
"links" | "rechts") ersetzen magische Strings - Diskriminierte Unions: gemeinsames Feld (
art) bestimmt die Variante neverimdefaulterzwingt Vollständigkeit- Eigene Typprüfer:
x is Typ
Übungsaufgabe
Modelliere eine Zahlungsart als diskriminierte Union (karte, paypal, rechnung) mit unterschiedlichen Feldern und schreibe eine Funktion, die jede Art als Text beschreibt.
Quiz zur Selbstkontrolle
Was ist Narrowing?
- TypeScript engt den Typ innerhalb von Prüfungen ein (richtig)
- Verkleinern von Bildern
- Ein Fehler
- Das Löschen von Typen
Wozu dient ein gemeinsames Feld wie art in einer Union?
- Es unterscheidet die Varianten (Diskriminante) (richtig)
- Es speichert die Länge
- Es ist nur ein Kommentar
- Es verhindert Fehler automatisch
Wofür benutzt man never im default-Zweig?
- Damit der Compiler fehlende Fälle meldet (richtig)
- Um das Programm zu beenden
- Um Variablen zu löschen
- Um Typen zu ändern
Weiter im Kurs
Zurück: Objekte, Interfaces und Typ-Aliase
Weiter: Arrays, Tupel und Enums
Alle Kapitel: TypeScript im Überblick