Poznajemy nieco głupie ćwiczenie z infer, które jednak może nas czegoś nauczyć. Inaczej nie da się tego tematu ugryźć, do dzieła zatem.
Ok, kod na pierwszy rzut oka wygląda genialnie:
type First<TArray extends any[]> = TArray extends [infer TFirst, ...any[]] ? TFirst : never;
Dobra, użyjmy sobie:
type First<TArray extends any[]> = TArray extends [infer TFirst, ...any[]] ? TFirst : never;
type FirstEx = First<[1,2,3]>
// type FirstEx = 1
Tylko musimy pamiętać, że to się tyczy tylko typów i literałów. Tak też będzie dobrze:
type First<TArray extends any[]> = TArray extends [infer TFirst, ...any[]] ? TFirst : never;
type FirstEx = First<[1,2,3]>
// type FirstEx = 1
type RetVals = [-1,0,1];
type FirstRetVal = First<RetVals>
//type FirstRetVal = -1
Ale z obiektami to nie przejdzie:
const arr1212 = [1,2,3,4, "5"];
type FirstEx2 = First<typeof arr1212>
// type FirstEx2 = never
Dodam, że as const jeszcze bardziej popsuje, po prostu nie będzie wtedy można tego wrzucić w First, bo się typ nie będzie zgadzać. Podobnie anotacja any[] nic nie da.
To tylko anotacja, a typeof będzie typ wnioskował po obiekcie. I w ogóle to jest coś, co się może zmieniać w runtime, więc niby czemu TS miałby umieć to wnioskować?
Najlepsze, co możemy zrobić to to:
const arr1212 = [1,2,3,4, "5"];
type First2<T extends any[]> = T extends [] ? never: T[0];
type FirstEx3 = First2<typeof arr1212>
//type FirstEx3 = string | number
Tyle tylko, ze to w zasadzie bez sensu. Podobnie kombinowanie z array unknown nic nie daje:
type First3<T extends Array<unknown>> = T extends [infer TFirst, ...unknown[]] ? TFirst : unknown;
type FirstEx4 = First3<typeof arr1212>
// type FirstEx4 = unknown
Krótko mówiąc to jest taki utility type, do używania na innych typach. Operator typeof czasem nam pozwala używać różnych util types z sukcesami na jakichś zmiennych (np. ReturnType, Parameters – bierzemy typeof nazwa funkcji i dalej jak zobaczymy definicję ReturnType czy Parameters to tam infer wchodzi do gry).
Czasami to się udaje, czasami nie. No chyba, że ja czegoś nie rozumiem, na pewno zagadnienie „dystrybucji” trzeba będzie w TS ogarnąć. Niedługo zrobię materiał o infer i niektórych util types, jak one wyglądają „pod spodem”.
Do następnego razu!