programowanieProgramista Fullstack

Opisz mechanizm automatycznie uzyskiwanych typów (ReturnType, Parameters) w TypeScript. Do czego są używane, jakie są niuanse pracy przy typizacji złożonych funkcji (na przykład z przeciążeniem)?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

ReturnType<T> i Parameters<T> to typy pomocnicze TypeScript, które pozwalają na automatyczne wyprowadzanie typu zwracanego przez funkcję (ReturnType) lub tablicy typów jej parametrów (Parameters).

Jest to szczególnie przydatne dla zapewnienia zgodności typów między różnymi częściami aplikacji oraz do realizacji ogólnych opakowań.

Przykład użycia:

function fn(a: number, b: string): boolean { return b.length > a; } type FnReturn = ReturnType<typeof fn>; // boolean type FnParams = Parameters<typeof fn>; // [number, string]

Niuanse z przeciążeniem funkcji: Przy przeciążeniu funkcji ReturnType definiuje ostatnią wersję sygnatury, a Parameters — wszystkie możliwe przeciążenia:

function overloaded(x: number): number; function overloaded(x: string): string; function overloaded(x: any): any { return x; } type OverRet = ReturnType<typeof overloaded>; // any type OverParams = Parameters<typeof overloaded>; // [any]

Oznacza to, że typizacja typów pomocniczych nie zawsze „widzi” wszystkie przeciżenia, dlatego statyczna typizacja staje się mniej przewidywalna.

Pytanie z podstępem.

Czy za pomocą ReturnType i Parameters można uzyskać typy wszystkich możliwych przeciżeń niestandardowej funkcji, definiując każde przeciżenie osobno?

Odpowiedź:

Nie. Typy pomocnicze ReturnType i Parameters analizują tylko “połączoną” sygnaturę funkcji — tak jak jest opisana dla realizacji. Nie pozwalają na uzyskanie typów każdej indywidualnej przeciżenia — tylko ostatecznej zrealizowanej sygnatury.

Przykład:

type P = Parameters<typeof overloaded>; // [any], a nie [number], [string]

Przykłady rzeczywistych błędów z powodu braku znajomości niuansów tematu


Historia

Programiści napisali opakowanie aroundMethod, używając ReturnType<T> do typizacji wartości zwracanej. Przy tym funkcja-opakowanie była stosowana do przeciążonej funkcji. Efekt: typy były zbyt ogólne (any), a w przypadku błędów kompilator nie sygnalizował niezgodności wartości zwracanych. Późno odkryto błąd przy pracy z booleanami zamiast stringów.


Historia

W próbie wyodrębnienia parametrów dla wielu funkcji API przez Parameters<T>, programista nie uwzględnił przeciżeń metod. Pojawił się problem z “błędnymi” typami, gdzie oczekiwano [string, number], a otrzymano [any]. Testy jednostkowe nie wychwytywały tego błędu z powodu montażu przez realizację, a rzeczywiści użytkownicy API napotkali błędy na produkcji.


Historia

Migrując duży kod z JavaScript do TypeScript, programiści wszystko typizowali przez ReturnType. Później zrozumieli, że realizacja znacznie różni się od deklaracji przeciżeń. Z tego powodu scenariusze z błędnymi argumentami powodowały nieoczekiwane wyjątki runtime (na przykład, TypeError: x is undefined).