Rekurencja na poziomie typów
Iteruj po typach za pomocą rekurencyjnych typów warunkowych
Rekurencja na poziomie typów to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 4 lekcji w sumie.
Rekurencja w typach
Typ warunkowy może odwoływać się do samego siebie. W ten sposób język typów zyskuje pętle. Większość rekurencji na poziomie typów przechodzi przez krotkę element po elemencie, oddzielając pierwszy element i wywołując rekurencję dla reszty.
type Length<T extends unknown[]> =
T extends [unknown, ...infer Rest]
? Length<Rest>
: 0;
// (this counts down to a base case)Przypadek bazowy
Każda rekurencja wymaga warunku zakończenia. W przypadku krotek jest nim zazwyczaj pusta krotka. Gdy wzorzec [head, ...rest] przestaje pasować, osiągnięto koniec i zwracany jest stały wynik.
type IsEmpty<T extends unknown[]> =
T extends [] ? true : false;
type A = IsEmpty<[]>; // true
type B = IsEmpty<[1, 2]>; // falsePierwszy element i reszta
Podstawowa operacja polega na podzieleniu krotki na pierwszy element i pozostałą krotkę za pomocą infer oraz wzorca z operatorem rozproszenia.
type Head<T extends unknown[]> = T extends [infer H, ...unknown[]] ? H : never;
type Tail<T extends unknown[]> = T extends [unknown, ...infer R] ? R : [];
type A = Head<[1, 2, 3]>; // 1
type B = Tail<[1, 2, 3]>; // [2, 3]Przetwarzanie element po elemencie
Połączenie pierwszego elementu, reszty i rekurencji pozwala przekształcić całą krotkę. ToStrings odtwarza krotkę, zastępując typ każdego elementu typem string.
type ToStrings<T extends unknown[]> =
T extends [infer H, ...infer R]
? [string, ...ToStrings<R>]
: [];
type A = ToStrings<[1, true, 3]>; // [string, string, string]Wzorzec akumulatora
Często wynik buduje się w dodatkowym parametrze nazywanym akumulatorem. Zaczyna on jako pusty i rośnie przy każdym kroku. Pozwala to uniknąć ponownego przechodzenia przez strukturę i jest standardową techniką tworzenia pętli na poziomie typów.
type Reverse<T extends unknown[], Acc extends unknown[] = []> =
T extends [infer H, ...infer R]
? Reverse<R, [H, ...Acc]>
: Acc;
type A = Reverse<[1, 2, 3]>; // [3, 2, 1]Przechodzenie przez akumulator
Prześledźmy Reverse<[1,2,3]>:
- Krok 1: H=1, Acc staje się [1]
- Krok 2: H=2, Acc staje się [2,1]
- Krok 3: H=3, Acc staje się [3,2,1]
- Krotka jest pusta, zwracany jest Acc = [3,2,1]
Akumulator przenosi wynik przez każde rekurencyjne wywołanie.
type R = Reverse<["a", "b"]>; // ["b", "a"]Rekurencja po uniach
Można również użyć rekurencji do połączenia ciągów znaków w jedną całość. W tym przykładzie elementy krotki są łączone w jeden typ literału tekstowego, rozdzielony separatorem.
Notacja: w rzeczywistym TypeScript typy literałów szablonowych zapisuje się jako ciągi znaków ograniczone grawisami, zawierające miejsca na interpolację dollar-brace. W tych fragmentach pokazujemy ten wzorzec jako Tpl<...>, wymieniając każdą część w kolejności; na przykład szablon z grawisami dopasowujący dosłowny prefiks, a następnie Rest, zapisujemy jako Tpl<'prefix', infer Rest>.
type Join<T extends string[], Sep extends string = ','> =
T extends [infer H extends string, ...infer R extends string[]]
? R extends []
? H
: Tpl<H, Sep, Join<R, Sep>>
: '';
// Tpl<H, Sep, ...> builds a template literal type joining the parts
type A = Join<['a', 'b', 'c']>; // 'a,b,c'Zliczanie za pomocą rekurencji
Rekurencja połączona z akumulatorem może służyć do zliczania. Należy zbudować krotkę elementów unknown o tej samej długości co dane wejściowe, a następnie odczytać jej length. Z tej techniki będą Państwo często korzystać w kursie arytmetyki.
type Count<T extends unknown[], Acc extends unknown[] = []> =
T extends [unknown, ...infer R]
? Count<R, [unknown, ...Acc]>
: Acc["length"];
type A = Count<["x", "y", "z"]>; // 3Filtrowanie za pomocą rekurencji
Przechodząc przez krotkę, należy zachować tylko elementy spełniające określony warunek i pominąć pozostałe. Aby pominąć element, nie należy dodawać go do akumulatora.
type KeepStrings<T extends unknown[], Acc extends unknown[] = []> =
T extends [infer H, ...infer R]
? H extends string
? KeepStrings<R, [...Acc, H]>
: KeepStrings<R, Acc>
: Acc;
type A = KeepStrings<[1, "a", 2, "b"]>; // ["a", "b"]Ograniczenia głębokości rekurencji
Kompilator ogranicza głębokość rekurencji (historycznie do około 50 poziomów, choć optymalizacje rekurencji ogonowej pozwalają w niektórych wzorcach na więcej). W przypadku bardzo dużych krotek może pojawić się błąd Type instantiation is excessively deep. Aby podnieść ten limit, należy stosować styl z akumulatorem, czyli rekurencję ogonową.
type Repeat<T, N extends number, Acc extends T[] = []> =
Acc["length"] extends N ? Acc : Repeat<T, N, [...Acc, T]>;
type A = Repeat<0, 3>; // [0, 0, 0]Połączenie wszystkiego
Podział na pierwszy element i resztę, przypadek bazowy oraz akumulator to trzy składniki niemal każdej pętli na poziomie typów. Dzięki nim można w systemie typów mapować, filtrować, odwracać, zliczać i łączyć krotki.
type MapToPairs<T extends unknown[], Acc extends unknown[] = []> =
T extends [infer H, ...infer R]
? MapToPairs<R, [...Acc, [H, H]]>
: Acc;
type A = MapToPairs<[1, 2]>; // [[1, 1], [2, 2]]Szybkie sprawdzenie
Proszę sprawdzić rozumienie wzorca akumulatora.
Podsumowanie
Mogą już Państwo tworzyć pętle na poziomie typów.
- Typy warunkowe odwołujące się do samych siebie tworzą rekurencję.
- Krotki należy dzielić na
[H, ...R]i wywoływać rekurencję dla reszty. - Przypadek bazowy (pusta krotka) zatrzymuje pętlę.
- Akumulator buduje wynik i umożliwia głęboką rekurencję.
Następnie: specjalne zachowanie typów warunkowych w przypadku unii.
Często zadawane pytania
Czy lekcja „Rekurencja na poziomie typów” jest bezpłatna?
Tak — pełny tekst „Rekurencja na poziomie typów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Rekurencja na poziomie typów”?
Iteruj po typach za pomocą rekurencyjnych typów warunkowych Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?
Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Rekurencja na poziomie typów”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?
Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Typy jako język obliczeń
- Warunki na poziomie typów
- Rekurencja na poziomie typów
- Rozdzielające typy warunkowe