Historia pytania: W JavaScript funkcje zwrotne są powszechnie używane, ale ich sygnatury często są nieoczywiste. W TypeScript należy wyraźnie określić typy parametrów i wartości zwracanej, w przeciwnym razie łatwo można napotkać luki w bezpieczeństwie typów.
Problem: Niewłaściwe lub niedokładne typowanie funkcji zwrotnej prowadzi do nieokreślonych typów argumentów i wyników, komplikuje pracę z kontekstem (this), łamie automatyczne sprawdzanie błędów przez kompilator i utrudnia refaktoryzację.
Rozwiązanie: Należy wyraźnie określać typ funkcji zwrotnej, wskazywać typy przekazywanych parametrów, poprawnie obsługiwać opcjonalne argumenty i wartość zwracaną, a w razie potrzeby wyraźnie ustalać typ kontekstu.
Przykład kodu:
type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('Pusta string')); else cb(null, data.toUpperCase()); }, 100); }
Kluczowe cechy:
Co się stanie, jeśli nie określisz typu wartości zwracanej funkcji zwrotnej?
TypeScript zaakceptuje dowolny typ zwracany (na przykład undefined, void, Promise), co może prowadzić do niespodzianek w asynchronicznych łańcuchach lub przy zwracaniu wartości "domyślnych".
type BadCallback = (data: string) => any; // dowolny wynik, brak kontroli
Czy można pisać callback jako Function lub (...args: any[]) => any?
Nie można. To usuwa całą ochronę typów, znika informacja o liczbie parametrów, ich typach i typie zwracanym. Takie podejście jest droższe niż całkowita rezygnacja z TypeScript.
Jak typować funkcję z kontekstem this?
Użyj pierwszego parametru this w sygnaturze funkcji lub rzuć przez bind. Na przykład:
interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };
W projekcie callback zadeklarowano jako (...args: any[]) => any. Przy aktualizacji logiki biznesowej sygnatura się zmieniła, callback przestał przekazywać niezbędne argumenty, błędy ujawnili się dopiero na produkcji.
Zalety:
Wady:
Wprowadzono restrykcyjne typy: opisano interfejsy funkcji zwrotnych, zaczęto wyraźnie określać typ this i typ zwracany. Kompilator zaczął wychwytywać błędy przed wdrożeniem, uprościła się refaktoryzacja i wsparcie dla naprawy błędów.
Zalety:
Wady: