Fehlerbehandlung in TypeScript: fortgeschrittene try/catch-Techniken

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Fortgeschrittene Fehlerbehandlung in TypeScript: Von try/catch zu typsicheren Lösungen



Fehlerbehandlung ist ein kritischer Aspekt der Entwicklung mit TypeScript. Das grundlegende try/catch reicht für komplexe Anwendungen oft nicht aus. In diesem Artikel betrachten wir fortgeschrittene Techniken, die helfen, den Code zuverlässiger, vorhersagbarer und typsicherer zu machen.



1. Das Problem des standardmäßigen try/catch: Typverlust



Der Hauptnachteil des klassischen catch ist, dass die Fehlervariable den Typ unknown (oder any in älteren Versionen) hat. Dies zwingt den Entwickler, den Typ manuell zu überprüfen:



try {  riskyOperation();} catch (error) {  // error: unknown  if (error instanceof Error) {    console.error(error.message);  } else {    console.error('Unbekannter Fehler', error);  }}


Lösung: Erstellung eines Hilfsprogramms für typisierten Fehlerabfang:



function getErrorMessage(error: unknown): string {  if (error instanceof Error) return error.message;  if (typeof error === 'string') return error;  if (error && typeof error === 'object' && 'message' in error) {    return String((error as { message: unknown }).message);  }  return 'Ein unbekannter Fehler ist aufgetreten';}

try { riskyOperation();} catch (error) { console.error(getErrorMessage(error));}


2. Benutzerdefinierte Fehlerklassen mit typisierten Daten



Die Erstellung einer Fehlerhierarchie ermöglicht es, das Problem genau zu identifizieren und zusätzliche Daten zu übergeben:



// Basisklasseclass AppError extends Error {  constructor(    message: string,    public readonly code: number,    public readonly isOperational: boolean = true  ) {    super(message);    this.name = 'AppError';  }}

// Spezialisierte Fehlerclass ValidationError extends AppError { constructor( message: string, public readonly field: string, public readonly invalidValue: unknown ) { super(message, 400); this.name = 'ValidationError'; }}

class NotFoundError extends AppError { constructor(entity: string, id: string) { super(`${entity} mit ID ${id} nicht gefunden`, 404, false); this.name = 'NotFoundError'; }}

// Verwendungfunction findUser(id: string): User { if (!validateId(id)) { throw new ValidationError('Ungültige ID', 'id', id); } const user = db.findUser(id); if (!user) { throw new NotFoundError('Benutzer', id); } return user;}

try { const user = findUser('123');} catch (error) { if (error instanceof NotFoundError) { // error.code === 404, error.message enthält Beschreibung console.warn(error.message); } else if (error instanceof ValidationError) { // error.field und error.invalidValue sind verfügbar console.error(`Fehler im Feld ${error.field}: ${error.message}`); } else if (error instanceof AppError) { console.error(`Anwendungsfehler (Code ${error.code}): ${error.message}`); }}


3. Discriminated Unions für die Fehlerbehandlung



Dieses Muster ermöglicht die Verarbeitung von Operationsergebnissen ohne Ausnahmen, indem eine Vereinigung von Typen mit einem Diskriminanten verwendet wird:



// Ergebnistyp mit Diskriminanttype Result<T, E = Error> =   | { success: true; data: T }  | { success: false; error: E };

// Funktion, die ein Result zurückgibtfunction safeDivide(a: number, b: number): Result<number, string> { if (b === 0) { return { success: false, error: 'Division durch Null' }; } return { success: true, data: a / b };}

// Verwendungconst result = safeDivide(10, 0);

if (result.success) { // TypeScript weiß, dass result.data — number ist console.log(`Ergebnis: ${result.data}`);} else { // result.error — string console.error(`Fehler: ${result.error}`);}

// Komplexeres Beispiel mit benutzerdefinierten Fehlerntype UserResult = Result<

Blogs

Buchempfehlungen