Konstrukcje
Variance annotations
`in` i `out` mówią, jak generyk zachowuje się, gdy zmienia się jego parametr — co TypeScript inaczej ustala sam.
Czym jest
Dodane w 4.7 i nietypowe o tyle, że nic nie zmieniają w tym, co legalne: TypeScript i tak wnioskuje wariancję strukturalnie. Dają szybkość i intencję — kompilator może pominąć porównanie strukturalne, a czytelnik zostaje wprost poinformowany, czy `Box<string>` może zastąpić `Box<string | number>`. `out` znaczy, że parametr jest produkowany, `in` że konsumowany, `in out` oba naraz.
Przykłady
Producer<string> extends Producer<string | number> ? true : false
→trueKowariantne: coś, co produkuje teksty, nada się wszędzie tam, gdzie oczekiwane jest produkujące teksty-lub-liczby.
Consumer<string | number> extends Consumer<string> ? true : false
→trueKontrawariantne i kierunek się odwraca: coś, co przyjmuje więcej, nada się wszędzie tam, gdzie oczekiwane jest przyjmujące mniej.
Consumer<string> extends Consumer<string | number> ? true : false
→falseA w drugą stronę zawodzi — i to właśnie po to ta adnotacja tam stoi.
Każdy rozwinięty typ powyżej wypisał TypeScript 5.9.3, nie ręka człowieka.
Czego nie robi
- Nie czynią legalnym nic, co nie było. Zaadnotuj błędnie, a kompilator odrzuci adnotację, a nie użycie — sprawdza twoje twierdzenie względem struktury.
- Nie są potrzebne w większości typów. Sięgaj po nie przy dużych rekurencyjnych generykach, gdzie wnioskowanie wariancji jest mierzalnie wolne, a nie ze względów stylu.
Wniosek
Wariancja to reguła rozstrzygająca, kiedy jeden generyk może zastąpić inny. Polegasz na niej od pierwszej tablicy; te słowa kluczowe pozwalają jedynie powiedzieć to na głos.