Hintergrund: In JavaScript werden Callback-Funktionen überall verwendet, aber ihre Signaturen sind oft nicht offensichtlich. In TypeScript sollte man die Typen der Parameter und des Rückgabewerts explizit angeben, da man sonst leicht Typensicherheitseinbußen erleidet.
Problem: Falsche oder lax typisierte Callbacks führen zu unbestimmten Typen von Argumenten und Ergebnissen, erschweren die Arbeit mit dem Kontext (this), brechen die automatische Fehlerprüfung durch den Compiler und erschweren das Refactoring.
Lösung: Man muss den Typ der Callback-Funktion explizit definieren, die Typen der übergebenen Parameter angeben, optionale Argumente und Rückgabewerte korrekt behandeln und bei Bedarf den Typ des Kontexts klar definieren.
Beispielcode:
type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('Leerer String')); else cb(null, data.toUpperCase()); }, 100); }
Wesentliche Merkmale:
Was passiert, wenn man den Rückgabetyp des Callbacks nicht angibt?
TypeScript akzeptiert jeden Rückgabewert (zum Beispiel undefined, void, Promise), was zu Überraschungen in asynchronen Ketten oder beim Zurückgeben von „Standard“-Werten führen kann.
type BadCallback = (data: string) => any; // beliebiges Ergebnis, keine Kontrolle
Kann man Callback als Function oder (...args: any[]) => any schreiben?
Nein. Das entfernt den gesamten Typenschutz, die Informationen über die Anzahl der Parameter, deren Typen und den Rückgabewert gehen verloren. Dieser Ansatz ist teurer als die vollständige Vermeidung von TypeScript.
Wie typisiert man eine Funktion mit dem Kontext this?
Verwenden Sie den ersten Parameter this in der Funktionssignatur oder casten Sie über bind. Zum Beispiel:
interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };
Im Projekt wurde der Callback als (...args: any[]) => any deklariert. Bei der Aktualisierung der Geschäftslogik änderte sich die Signatur, der Callback übermittelte nicht mehr die erforderlichen Argumente, Bugs traten erst in der Produktion auf.
Vorteile:
Nachteile:
Strenge Typen wurden eingeführt: Interfaces für Callbacks wurden beschrieben, der Typ von this und der Rückgabewert wurden klar angegeben. Der Compiler begann, Fehler vor dem Deployment zu erkennen, und das Refactoring sowie der Support für Bugfixes wurden einfacher.
Vorteile:
Nachteile: