typescript / expert
Snippet
Tail-Call Recursive Conditional Types for Zero-Cost Type Processing
TypeScript 4.5+ optimizes recursive conditional types when structured using tail-call optimization patterns. By passing an accumulator type parameter (Acc), the compiler avoids exceeding maximum call stack depth limits when transforming large tuple structures at compile time.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
type TailRecReverse<T extends readonly unknown[], Acc extends readonly unknown[] = []> =T extends readonly [infer Head, ...infer Tail]? TailRecReverse<Tail, [Head, ...Acc]>: Acc;type AssertEqual<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;type SampleTuple = readonly [string, number, boolean, symbol];type Reversed = TailRecReverse<SampleTuple>;type IsCorrect = AssertEqual<Reversed, readonly [symbol, boolean, number, string]>;const testPass: IsCorrect = true;
Breakdown
1
type TailRecReverse<T extends readonly unknown[], Acc extends readonly unknown[] = []> =
Defines a generic type accepting a read-only tuple and an accumulator array defaulting to an empty tuple.
2
T extends readonly [infer Head, ...infer Tail]
Pattern matches the tuple to extract the first element (Head) and the remaining elements (Tail).
3
? TailRecReverse<Tail, [Head, ...Acc]>
Recursively invokes the tail-call type by prepending Head to Acc in the accumulator argument position.
4
type AssertEqual<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
Verifies structural equality of two types at compile-time without distributive conditional behavior.