Fehlerbehandlung mit Typen in TypeScript
Fehlerbehandlung mit Typen
~16 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Unsere leiheAus()-Methode (Kapitel 14) gibt bisher nur boolean zurück – Erfolg oder Misserfolg, aber KEINE Information, WARUM etwas fehlgeschlagen ist. Dieses Kapitel zeigt zwei bessere Muster: eigene Error-Klassen und das "Result-Type"-Pattern.
Ein grundlegendes TypeScript-Problem: catch(error)
try {
bibliothek.leiheAus('123');
} catch (error) {
console.log(error.message); // Fehler! error hat den Typ 'unknown', NICHT 'Error'
}In modernem TypeScript (seit Version 4.4, strict aktiviert) hat error in einem catch-Block standardmäßig den Typ unknown (Kapitel 4) – NICHT Error, weil JavaScript technisch erlaubt, ALLES zu werfen (throw 'ein String', throw 42 sind beide gültig). TypeScript ZWINGT Sie, das zu berücksichtigen.
try {
bibliothek.leiheAus('123');
} catch (error) {
if (error instanceof Error) { // Type Narrowing aus Kapitel 19!
console.log(error.message); // ✓ jetzt erlaubt - error ist als Error erkannt
} else {
console.log('Unbekannter Fehler:', error);
}
}Eigene Error-Klassen
export class BibliotheksFehler extends Error {
constructor(message: string) {
super(message);
this.name = 'BibliotheksFehler';
}
}
export class MediumNichtGefundenFehler extends BibliotheksFehler {
constructor(public readonly isbn: string) {
super(`Medium mit ISBN ${isbn} wurde nicht gefunden.`);
this.name = 'MediumNichtGefundenFehler';
}
}
export class MediumNichtVerfuegbarFehler extends BibliotheksFehler {
constructor(public readonly isbn: string, public readonly aktuellerStatus: string) {
super(`Medium ${isbn} ist nicht verfügbar (Status: ${aktuellerStatus}).`);
this.name = 'MediumNichtVerfuegbarFehler';
}
}GENAU Vererbung aus Kapitel 13, angewendet auf die eingebaute Error-Klasse – MediumNichtGefundenFehler und MediumNichtVerfuegbarFehler tragen ZUSÄTZLICHE, typisierte Informationen (isbn, aktuellerStatus) über den reinen message-String hinaus.
// In Bibliothek.ts:
leiheAus(isbn: string): void {
const medium = this.bestand.find((m) => m.isbn === isbn);
if (!medium) {
throw new MediumNichtGefundenFehler(isbn);
}
if (medium.status !== 'verfuegbar') {
throw new MediumNichtVerfuegbarFehler(isbn, medium.status);
}
medium.status = 'ausgeliehen';
}try {
bibliothek.leiheAus('999');
} catch (error) {
if (error instanceof MediumNichtGefundenFehler) {
console.log(`Bitte ISBN prüfen: ${error.isbn}`); // typisierter Zugriff auf isbn!
} else if (error instanceof MediumNichtVerfuegbarFehler) {
console.log(`Status war: ${error.aktuellerStatus}`);
}
}Alternative: das Result-Type-Pattern
throw/catch hat einen Nachteil: der Funktions-TYP selbst zeigt NICHT, dass ein Fehler möglich ist – Aufrufer müssen die Dokumentation lesen oder es "einfach wissen". Das Result-Type-Pattern macht Fehler EXPLIZIT Teil der Signatur:
export type Result<T, E = Error> =
| { erfolg: true; wert: T }
| { erfolg: false; fehler: E };
export function erfolg<T>(wert: T): Result<T, never> {
return { erfolg: true, wert };
}
export function fehlgeschlagen<E>(fehler: E): Result<never, E> {
return { erfolg: false, fehler };
}leiheAus(isbn: string): Result<void, BibliotheksFehler> {
const medium = this.bestand.find((m) => m.isbn === isbn);
if (!medium) {
return fehlgeschlagen(new MediumNichtGefundenFehler(isbn));
}
if (medium.status !== 'verfuegbar') {
return fehlgeschlagen(new MediumNichtVerfuegbarFehler(isbn, medium.status));
}
medium.status = 'ausgeliehen';
return erfolg(undefined);
}
const ergebnis = bibliothek.leiheAus('123');
if (ergebnis.erfolg) {
console.log('Ausleihe erfolgreich!'); // TypeScript weiß: ergebnis.wert existiert (Discriminated Union, Kapitel 9!)
} else {
console.log(`Fehler: ${ergebnis.fehler.message}`); // TypeScript weiß: ergebnis.fehler existiert
}Result<T, E> ist eine Discriminated Union (Kapitel 9) MIT Generics (Kapitel 17) kombiniert – der erfolg-Boolean ist der Diskriminator. Der GROSSE Vorteil: der RÜCKGABETYP Result<void, BibliotheksFehler> zeigt SOFORT, ohne Dokumentation zu lesen, dass diese Methode fehlschlagen KANN – ein Aufrufer, der ergebnis.wert liest, OHNE vorher ergebnis.erfolg zu prüfen, bekommt einen KOMPILIERZEIT-Fehler, nicht erst einen Laufzeit-Crash.
| Muster | Wann geeignet |
|---|---|
| throw/catch | Vertraut, JavaScript-Standard, funktioniert gut für UNERWARTETE, seltene Fehler (Programmierfehler, kaputte Daten). |
| Result-Type | Fehler sind Teil der TYP-Signatur, ERZWUNGENE Behandlung durch den Compiler, ideal für ERWARTETE, häufige "Fehlerfälle" (Validierung, Geschäftslogik-Regeln wie "Buch nicht verfügbar"). |
Tipp: Faustregel: throw für WIRKLICH AUSSERGEWÖHNLICHE Situationen (ein Bug, korrupte Daten, ein Netzwerk, das komplett unerreichbar ist), Result-Type für ERWARTBARE "Fehlerpfade", die Teil des normalen Programmablaufs SIND ("Buch schon ausgeliehen" ist kein BUG, sondern ein normaler Geschäftsfall). Beide Muster können im selben Projekt nebeneinander existieren.