programowanieFrontend developer

Jak poprawnie typować funkcję zwrotną (callback) w TypeScript i jakie pułapki należy uwzględnić podczas pracy z kontekstem i typami błędów?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

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:

  • Zawsze określaj typy wszystkich parametrów funkcji zwrotnej.
  • Opisuj typ zwracany, nawet jeśli to void.
  • W razie potrzeby wyraźnie ustalaj typ this (na przykład poprzez funkcję z kontekstem).

Pytania z pułapką.

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'; };

Typowe błędy i antywzorce

  • Nietypowane callbacki (any lub Function)
  • Brak typu zwracanego w sygnaturze funkcji
  • Niedopasowanie typu this prowadzi do losowych błędów w czasie wykonywania

Przykład z życia

Negatywny przypadek

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:

  • Łatwiej kompilować i integrować kod zewnętrzny

Wady:

  • Brak ochrony na poziomie typów
  • Trudności w aktualizacji

Pozytywny przypadek

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:

  • Bezpieczeństwo typów
  • Sprawdzanie zmian sygnatur w czasie kompilacji

Wady:

  • Trochę skomplikowane typowanie, wzrósł udział boilerplate