Historia pytania:
Funkcje zwrotne — to powszechna praktyka w JS i TS do programowania asynchronicznego i delegowania odpowiedzialności. W TypeScript typowanie takich funkcji jest ważną częścią zapewnienia bezpieczeństwa, zwłaszcza jeśli parametry mogą być opcjonalne lub mieć wartości domyślne.
Problem:
W dynamicznym JS brak typowania argumentów callback prowadzi do błędów w przekazywaniu wartości, zamieszania z undefined i niewłaściwego porządku parametrów. W TypeScript typowanie jest wymagane, aby uniknąć podobnych problemów, ale na zewnątrz trudno jest uwzględnić wszystkie niuanse związane z opcjonalnością, porządkiem i wartościami domyślnymi.
Rozwiązanie:
Wyraźnie określać typy wszystkich parametrów, opcjonalne parametry oznaczać znakiem zapytania, a wartości domyślne – podawać bezpośrednio przy deklaracji funkcji, pamiętając o poprawnym opisywaniu ich w typie.
Przykład kodu:
function fetchData( url: string, callback: (data: any, error?: Error) => void ) { // ... } // Callback z opcjonalnym parametrem error fetchData('/api', (data, error) => { if (error) { // obsługa } else { // sukces } }); // Callback z parametrem domyślnym function process( cb: (x: number, y?: number) => void = (x, y = 10) => { /* ... */ } ) { /* ... */ }
Główne cechy:
Czy konsument callbacka musi wyraźnie uwzględniać wszystkie parametry, w tym opcjonalne?
Nie, może pominąć opcjonalne parametry, a TypeScript nie zgłosi błędu — obsługa odbywa się prawidłowo dzięki składni znaku zapytania.
Czy można uczynić pierwszy parametr w callbacku opcjonalnym, a drugi — obowiązkowym?
Nie. Parametry opcjonalne zawsze muszą być na końcu listy argumentów. Naruszenie porządku spowoduje błąd typowania.
Co się stanie, jeśli nie oznaczymy opcjonalności parametru, ale nie przekażemy go w miejscu wywołania?
TypeScript zgłosi błąd — jeśli parametr jest obowiązkowy, musi być przekazany. Tylko opcjonalne lub te z domyślną wartością mogą być pominięte.
Oznaczyliśmy drugi argument callbacka jako obowiązkowy, a w wywołaniu go nie przekazaliśmy. Otrzymaliśmy błąd kompilacji.
Zalety:
Wady:
Typowaliśmy callback z opcjonalnym parametrem:
(cb: (x: number, y?: number) => void)
lub zadaliśmy domyślną wartość:
f = (x: number, y = 10) => { ... }
Zalety:
Wady: