Zaimplementuj `Subtract<A, B>` zwracający `A − B` jako literał liczbowy. Gdy `B` jest większe od `A`, odpowiedzią jest `never` — nie ma ujemnych długości krotek.
01
Spróbuj rozwiązać samodzielnie
Par 5
Zagadka
type-level-subtract.ts
type BuildTuple<N extendsnumber, Acc extendsunknown[] = []> =
Acc['length'] extends N ? Acc : BuildTuple<N, [...Acc, unknown]>
type Subtract<A extendsnumber, B extendsnumber> = ???
Podejście 1 z 5Jeszcze nie sprawdzone
Zastąp ??? — rozwiązanie sprawdzamy przypadkami poniżej. Tab wcina; naciśnij Escape, a potem Tab, by wyjść fokusem.
Testy
4
Subtract<5, 3>—
→ 2
Subtract<3, 3>—
→ 0
Subtract<10, 4>—
→ 6
Subtract<2, 5>—
→ never
Jak oceniamy test Dokładna równość typów, nie przypisywalność — przecięcie to nie to samo co spłaszczony obiekt.
Jak poszło innym
Tę zagadkę rozwiązało jak dotąd mniej niż 5 osób. Rozkład pojawi się, gdy próbka będzie na tyle duża, by coś znaczyć.
type Subtract<A extendsnumber, B extendsnumber> =
BuildTuple<A> extends [...BuildTuple<B>, ...infer Rest] ? Rest['length'] : never
Najczęstsza błędna odpowiedź
type Subtract<A extendsnumber, B extendsnumber> =
[...BuildTuple<A>, ...BuildTuple<B>]['length']
To dodawanie pod inną nazwą. Złączenie dwóch krotek może je tylko wydłużyć; odejmowanie musi krotkę *rozłożyć*, czyli wymaga dopasowania wzorca, a nie budowania.
Linia po linii
[...BuildTuple<B>, ...infer Rest]
Wzorzec ustala przedrostek dokładnie `B` elementów, a `Rest` pochłania resztę. Dopasowanie udaje się tylko wtedy, gdy obiekt jest co najmniej tak długi.
: never
Gdy `B > A`, przedrostka nie da się dopasować, warunek zawodzi i wypada `never` — uczciwa odpowiedź dla odejmowania, którego ta arytmetyka nie potrafi wyrazić.
Do zapamiętania
Budowanie krotek dodaje; ich rozkładanie odejmuje. Każda operacja arytmetyczna, jaką TypeScript potrafi na typach, to jeden z tych dwóch ruchów w przebraniu.