Przejdź do treści
webtype.orgDwanaście zagadnień · 11/12

Zagadnienie 11 z 12

Krotki wariadyczne

Krotki to jedyna struktura danych na poziomie typów, która ma długość — a więc jedyny licznik. Każda arytmetyka na typach, jaką zobaczysz, to przebrane liczenie elementów krotki.

Rozwinięcia łączą

type A = [1, 2]
type B = [3, 4]
type Joined = [...A, ...B]        // [1, 2, 3, 4]
type Prefixed = [0, ...A]         // [0, 1, 2]

type Len = Joined['length']       // 4  — a numeric literal type

Dla krotki o stałej długości `length` jest literałem liczbowym, a nie `number`. Ten jeden fakt umożliwia arytmetykę: zbuduj krotkę odpowiedniego rozmiaru, a potem odczytaj jej długość.

Dodawanie to złączenie, odejmowanie to dopasowanie

type Build<N extends number, Acc extends unknown[] = []> =
  Acc['length'] extends N ? Acc : Build<N, [...Acc, unknown]>

type Add<A extends number, B extends number> =
  [...Build<A>, ...Build<B>]['length']

type Sub<A extends number, B extends number> =
  Build<A> extends [...Build<B>, ...infer Rest] ? Rest['length'] : never

Budowanie krotki dodaje; rozkładanie odejmuje. Akumulator trzyma `unknown`, bo zawartość nie ma znaczenia — to zbiór kresek, a nie kolekcja czegokolwiek.

Element rest nie musi być ostatni

type Last<T> = T extends readonly [...unknown[], infer L] ? L : never
type Init<T> = T extends readonly [...infer I, unknown] ? I : never

Wzorzec krotki może zawierać dokładnie jeden element rest i wolno mu stać na początku. Tak dociera się do końca krotki bez liczenia.

Najczęstsza błędna odpowiedź

// Intent: subtract.
type Sub<A extends number, B extends number> =
  [...Build<A>, ...Build<B>]['length']
// That is addition with a different name — concatenating
// can only ever make the tuple longer.

Odejmowanie musi krotkę rozłożyć, czyli wymaga dopasowania wzorca, a nie budowania. Jeśli Twój typ arytmetyczny tylko rozwija, potrafi tylko dodawać.

Do zapamiętania

Długość krotki to jedyna liczba, którą system typów potrafi liczyć. Buduj, by dodać, rozkładaj, by odjąć, i spodziewaj się limitu rekurencji w okolicach tysiąca.

Ćwiczone w