0Pricing
TypeScript Academy · Lekcja

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]>; // false

Pierwszy 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"]>; // 3

Filtrowanie 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

  1. Typy jako język obliczeń
  2. Warunki na poziomie typów
  3. Rekurencja na poziomie typów
  4. Rozdzielające typy warunkowe
← Powrót do TypeScript Academy