Asynchrone Programmierung in TypeScript: vollständiger Leitfaden in der Praxis
Moderne Webentwicklung ist ohne asynchrone Operationen undenkbar: API-Anfragen, Datenbankarbeit, Dateilesen und Timer. TypeScript als Erweiterung von JavaScript behält nicht nur alle Möglichkeiten der asynchronen Programmierung, sondern fügt auch strenge Typisierung hinzu, wodurch der Code vorhersagbarer und sicherer wird. In diesem Leitfaden behandeln wir die wichtigsten Konzepte der Asynchronität in TypeScript – von grundlegenden Promises bis zu fortgeschrittenen Mustern – mit echten Codebeispielen.
1. Grundlagen: Promise und Typisierung
Ein Promise ist ein Objekt, das das Ergebnis einer asynchronen Operation darstellt, die erfolgreich abgeschlossen (fulfilled) oder abgelehnt (rejected) werden kann. TypeScript ermöglicht es, den Rückgabewert eines Promise streng zu typisieren.
// Beispiel eines typisierten Promisefunction fetchUserData(userId: number): Promise<{ name: string; email: string }> { return new Promise((resolve, reject) => { setTimeout(() => { if (userId > 0) { resolve({ name: 'Ivan Ivanov', email: 'ivan@example.com' }); } else { reject(new Error('Ungültige Benutzer-ID')); } }, 1000); });}
// VerwendungfetchUserData(1) .then(user => console.log(user.name)) // Ivan Ivanov .catch(error => console.error(error.message));Beachten Sie: Promise<{ name: string; email: string }> stellt sicher, dass wir im then ein Objekt genau mit diesen Feldern erhalten. Das vermeidet Fehler durch undefinierte Eigenschaften.
2. Async/Await: syntaktischer Zucker mit TypeScript
Die Schlüsselwörter async und await lassen asynchronen Code wie synchronen aussehen, ohne Leistungseinbußen. TypeScript bestimmt automatisch den Rückgabetyp einer async-Funktion als Promise<T>.
// Funktion gibt Promise<number> zurückasync function getDiscountPrice(price: number, discountPercent: number): Promise<number> { if (discountPercent < 0 || discountPercent > 100) { throw new Error('Ungültiger Rabattprozentsatz'); } // Simulation einer asynchronen Berechnung const discount = await calculateDiscountAsync(price, discountPercent); return price - discount;}
// Hilfsfunktionfunction calculateDiscountAsync(price: number, percent: number): Promise<number> { return Promise.resolve(price * percent / 100);}
// Verwendungasync function main() { try { const finalPrice = await getDiscountPrice(1000, 20); console.log(`Endpreis: ${finalPrice}`); // 800 } catch (error) { if (error instanceof Error) { console.error('Fehler:', error.message); } }}main();Wichtig: TypeScript erlaubt die Verwendung von await außerhalb einer async-Funktion nicht (außer auf oberster Ebene in Modulen mit bestimmten Einstellungen). Umwickeln Sie Aufrufe immer in eine async-Funktion oder verwenden Sie .then().
3. Fehlerbehandlung und fortgeschrittene Muster
Eine sorgfältige Fehlerbehandlung ist die Grundlage zuverlässigen asynchronen Codes. TypeScript hilft, Fehler bereits zur Kompilierzeit zu erkennen, aber die Logik der Fehlerbehandlung muss manuell geschrieben werden.
3.1. Fehlerbehandlung in async/await
async function safeFetchData(url: string): Promise<unknown> { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP-Fehler! Status: ${response.status}`); } return await response.json(); } catch (error) { // TypeScript schränkt den Typ auf Error ein if (error instanceof Error) { console.error('Anfragefehler:', error.message); // Kann einen Standardwert zurückgeben oder den Fehler weiterwerfen return null; } throw error; // Unbekannter Fehler