Type Narrowing und Type Guards in TypeScript
Type Narrowing und Type Guards
~17 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Zeit, das Versprechen aus Kapitel 9 einzulösen: WIE greift man auf typspezifische Eigenschaften innerhalb eines Union Types zu? Die Antwort heißt Type Narrowing – TypeScript ENGT den Typ einer Variable basierend auf Laufzeit-Prüfungen automatisch ein.
typeof: für primitive Typen
function formatiereId(id: string | number): string {
if (typeof id === 'string') {
return id.toUpperCase(); // TypeScript weiß HIER: id ist string
}
return id.toFixed(2); // TypeScript weiß HIER: id ist number (Ausschlussverfahren)
}typeof id === 'string' ist ein LAUFZEIT-Check (echtes JavaScript, existiert im kompilierten Code) – TypeScript ERKENNT dieses Muster automatisch und engt id INNERHALB des if-Blocks auf string ein, im else-Zweig (implizit über das return) auf number.
instanceof: für Klassen-Instanzen
function beschreibeMedium(medium: Buch | Hoerbuch): string {
if (medium instanceof Hoerbuch) {
return `${medium.titel}, gesprochen von ${medium.sprecher}`; // sprecher nur auf Hoerbuch!
}
return `${medium.titel}, ${medium.seitenzahl} Seiten`; // seitenzahl nur auf Buch!
}instanceof prüft, ob ein Objekt tatsächlich eine Instanz einer BESTIMMTEN Klasse ist – funktioniert NUR mit Klassen (nicht mit reinen Interfaces/Type-Aliases, da diese zur Laufzeit nicht existieren, siehe Kapitel 1).
der in-Operator: Eigenschaft-Existenz prüfen
interface Vogel {
fliegen(): void;
}
interface Fisch {
schwimmen(): void;
}
function bewege(tier: Vogel | Fisch): void {
if ('fliegen' in tier) {
tier.fliegen(); // TypeScript weiß: tier ist Vogel
} else {
tier.schwimmen(); // TypeScript weiß: tier ist Fisch
}
}in ist besonders nützlich für REINE Interfaces (ohne Klassen, also ohne instanceof-Option) – prüft zur Laufzeit, ob eine Eigenschaft/Methode auf dem Objekt EXISTIERT.
Discriminated Unions erneut: der eleganteste Weg
Kapitel 9 zeigte bereits das typ-Feld-Muster – jetzt verstehen wir, WARUM es funktioniert: if (treffer.typ === 'buch') ist strukturell IDENTISCH zu typeof-Narrowing, nur auf ein SELBST DEFINIERTES Literal-Feld statt einen eingebauten JavaScript-Typ angewendet.
Eigene Type Guards schreiben
function istHoerbuch(medium: Medium): medium is Hoerbuch {
return medium instanceof Hoerbuch;
}
const medien: Medium[] = [/* ... */];
const hoerbuecher = medien.filter(istHoerbuch);
// hoerbuecher hat den Typ Hoerbuch[], NICHT Medium[] -
// TypeScript versteht die Signatur 'medium is Hoerbuch' als Narrowing-Anweisungmedium is Hoerbuch (statt einfach boolean) ist eine "Type-Predicate"-Signatur – sie sagt TypeScript: "wenn diese Funktion true zurückgibt, ENGE den Typ des Parameters auf Hoerbuch ein". Das funktioniert AUCH bei Array.filter(), wie oben gezeigt – ein extrem nützliches, fortgeschrittenes Muster.
Erschöpfende Prüfung mit never
type Genre = 'Fantasy' | 'Krimi' | 'SachBuch';
function genreIcon(genre: Genre): string {
switch (genre) {
case 'Fantasy': return '????';
case 'Krimi': return '????';
case 'SachBuch': return '????';
default:
const nieErreicht: never = genre; // Fehler, WENN Genre um einen Wert erweitert wird,
// aber dieser switch nicht aktualisiert wurde!
throw new Error(`Unbekanntes Genre: ${nieErreicht}`);
}
}never aus Kapitel 4 in seiner nützlichsten Anwendung: wenn ALLE Fälle der Union bereits behandelt wurden, hat genre im default-Zweig korrekterweise den Typ never ("kann hier logisch nicht ankommen"). Wird Genre SPÄTER um 'Roman' erweitert, aber DIESER switch vergessen zu aktualisieren, zeigt TypeScript SOFORT einen Fehler an genau dieser Stelle – ein mächtiges Sicherheitsnetz gegen "vergessene" Fallunterscheidungen.
Tipp: Faustregel: typeof für primitive Typen, instanceof für Klassen, in für reine Interface-Eigenschaften, ein Diskriminator-Feld für selbstdefinierte Unions (der meist ELEGANTESTE Weg), eigene Type Guards (x is Y) für komplexere, wiederverwendbare Prüflogik. Die never-Technik ist optional, aber bei wachsenden Union Types sehr wertvoll.