Słowo kluczowe infer, czyli zmienne w typach warunkowych.
hejto.plDzisiaj coś krótkiego, bo dzień roboczy mi się masakrycznie przedłużył. Słowo kluczowe infer pozwala nam definiować swego rodzaju zmienne w typach warunkowych i wykorzystywać je do przeprowadzania dalszych operacji warunkowych. Możemy je też po prostu zwrócić.
Przejdźmy przez prosty przykład. Wyodrębnijmy typ zwracany przez funkcję:
type ReturnType<T> = T extends (...args: any\[\]) => infer R ? R : any;<br /> ```<br /> Na początku sprawdzamy czy typ generyczny **T** jest funkcją, jednocześnie deklarując zmienną **R** w miejscu tego, co powinno zostać zwrócone. Jeżeli **T** jest faktycznie funkcją to zwracamy **R**, jeżeli nie to zwracamy typ **any**.<br /> Teraz spójrzmy na coś bardziej skomplikowanego i przy okazji przekonajmy się, że faktycznie można używać zmiennych w dalszych rozważaniach warunkowych:<br /> ```<br /> type Awaited<T> = T extends null ? T : T extends object & { then(onfulfilled: infer F): any; } ? F extends (value: infer V, ...args: any) => any ? Awaited<V> : never : T<br /> ```<br /> Woah, to wygląda już ciekawiej. Dobra, lecimy od początku. Jeżeli typ **T** jest **null**, to zwracamy po prostu **T**. Dalej, jezeli **T** nie jest wartością prymitywną (typ **object** to wszystko, co nie prymitywne) i jest na nim zdefiniowane pole z funkcją **then** to wyciągamy typ **F** i znowu sprawdzamy czy **F** jest funkcją, wyciągamy typ **V** i rekursywnie wywołujemy na nim **Awaited**, bo pamiętajmy, że **Promise** można łączyć w łańcuchy.<br /> Ciężko to się czyta, szczególnie w takiej skondensowanej postaci. Mam nadzieję, że udało Wam się też załapać o co w tym wszystkim chodzi. ( ͡ʘ ͜ʖ ͡ʘ)<br /> Obserwuj tagi [#typescript](/tag/typescript) i [#magicznytypescript](/tag/magicznytypescript), aby być na bieżąco!
Przejdźmy przez prosty przykład. Wyodrębnijmy typ zwracany przez funkcję:
type ReturnType<T> = T extends (...args: any\[\]) => infer R ? R : any;<br /> ```<br /> Na początku sprawdzamy czy typ generyczny **T** jest funkcją, jednocześnie deklarując zmienną **R** w miejscu tego, co powinno zostać zwrócone. Jeżeli **T** jest faktycznie funkcją to zwracamy **R**, jeżeli nie to zwracamy typ **any**.<br /> Teraz spójrzmy na coś bardziej skomplikowanego i przy okazji przekonajmy się, że faktycznie można używać zmiennych w dalszych rozważaniach warunkowych:<br /> ```<br /> type Awaited<T> = T extends null ? T : T extends object & { then(onfulfilled: infer F): any; } ? F extends (value: infer V, ...args: any) => any ? Awaited<V> : never : T<br /> ```<br /> Woah, to wygląda już ciekawiej. Dobra, lecimy od początku. Jeżeli typ **T** jest **null**, to zwracamy po prostu **T**. Dalej, jezeli **T** nie jest wartością prymitywną (typ **object** to wszystko, co nie prymitywne) i jest na nim zdefiniowane pole z funkcją **then** to wyciągamy typ **F** i znowu sprawdzamy czy **F** jest funkcją, wyciągamy typ **V** i rekursywnie wywołujemy na nim **Awaited**, bo pamiętajmy, że **Promise** można łączyć w łańcuchy.<br /> Ciężko to się czyta, szczególnie w takiej skondensowanej postaci. Mam nadzieję, że udało Wam się też załapać o co w tym wszystkim chodzi. ( ͡ʘ ͜ʖ ͡ʘ)<br /> Obserwuj tagi [#typescript](/tag/typescript) i [#magicznytypescript](/tag/magicznytypescript), aby być na bieżąco!