Fehlerbehandlung in TypeScript: von try/catch zu zuverlässigem Code
TypeScript fügt JavaScript statische Typisierung hinzu, aber Laufzeitfehler bleiben ein wesentlicher Bestandteil der Entwicklung. Eine falsche Ausnahmebehandlung kann zum Absturz der Anwendung, zu Datenlecks oder zu Fehlfunktionen der Benutzeroberfläche führen. In diesem Artikel werden wir untersuchen, wie man Fehler in TypeScript effektiv behandelt, indem man integrierte Mechanismen und fortgeschrittene Patterns verwendet.
Basis try/catch in TypeScript
Das Konstrukt try/catch ist die Grundlage der Fehlerbehandlung. In TypeScript können wir im Gegensatz zu JavaScript den abgefangenen Fehler typisieren. Es gibt jedoch eine wichtige Nuance: Standardmäßig ist der Fehlertyp im catch-Block unknown, nicht Error.
try { const data = JSON.parse('ungültiges json'); console.log(data);} catch (error) { // error hat den Typ unknown if (error instanceof Error) { console.error('Ein Fehler ist aufgetreten:', error.message); } else { console.error('Unbekannter Fehler:', error); }}Warum ist das wichtig? In JavaScript kann man alles werfen: einen String, eine Zahl, ein Objekt. TypeScript schützt uns vor unsicherem Zugriff auf Fehlereigenschaften ohne Überprüfung. Es wird empfohlen, den Fehlertyp vor der Verwendung immer zu überprüfen.
Benutzerdefinierte Fehlerklassen
Für eine präzisere Fehlerbehandlung erstellen Sie eigene Fehlerklassen, die den integrierten Error erweitern. Dies ermöglicht es, Fehlertypen zu unterscheiden und zusätzliche Informationen zu übermitteln.
class ValidationError extends Error { constructor( public field: string, message: string ) { super(message); this.name = 'ValidationError'; }}
class NetworkError extends Error { constructor( public statusCode: number, message: string ) { super(message); this.name = 'NetworkError'; }}
function processUserData(data: unknown): void { if (!data || typeof data !== 'object') { throw new ValidationError('data', 'Ungültige Daten'); } if (!('email' in data)) { throw new ValidationError('email', 'Email ist erforderlich'); }}
try { processUserData({ name: 'Ivan' });} catch (error) { if (error instanceof ValidationError) { console.error(`Validierungsfehler im Feld ${error.field}: ${error.message}`); } else if (error instanceof NetworkError) { console.error(`Netzwerkfehler ${error.statusCode}: ${error.message}`); } else { console.error('Unbekannter Fehler:', error); }}Dieser Ansatz macht den Code selbstdokumentierend und vereinfacht das Debugging. Sie wissen immer, wo und warum ein Fehler aufgetreten ist.
Typisierung von Funktionen mit Fehlern: never und discriminated unions
TypeScript bietet leistungsstarke Werkzeuge für die Arbeit mit Fehlern auf Typebene. Verwenden Sie den Typ never für Funktionen, die immer eine Ausnahme werfen, und discriminated unions für die Rückgabe von Fehlern.
function throwError(message: string): never { throw new Error(message);}
// Discriminated union für das Ergebnistype Result<T> = | { success: true; data: T } | { success: false; error: string };
function fetchUser(id: number): Result<{ name: string }> { try { // Simulation einer Anfrage if (id <= 0) { return { success: false, error: 'Ungültige ID' }; } return { success: true, data: { name: 'Anna' } }; } catch (error) { return { success: false, error: 'Netzwerkfehler' }; }}
const result = fetchUser(1);if (result.success) { console.log('Benutzer:', result.data.name);} else { console.error('Fehler:', result.error);}Das Result-Pattern ermöglicht es, implizite Ausnahmen zu vermeiden und macht die Fehlerbehandlung