Reading — step 1 of 5
Learn
~1 min readType-Level Programming
Conditional types can recurse, enabling type-level computation.
Tuple manipulation:
type Reverse<T extends any[]> =
T extends [infer First, ...infer Rest]
? [...Reverse<Rest>, First]
: [];
type A = Reverse<[1, 2, 3]>; // [3, 2, 1]
type B = Reverse<['a', 'b']>; // ['b', 'a']
The [infer First, ...infer Rest] pattern destructures a tuple — first element + rest. Recurse, append First to the reversed rest.
Length of a tuple at type level:
type Length<T extends any[]> = T['length'];
type Three = Length<[1, 2, 3]>; // 3
Type-level arithmetic (limited but possible):
type BuildArray<N extends number, T extends any[] = []> =
T['length'] extends N ? T : BuildArray<N, [unknown, ...T]>;
type Add<A extends number, B extends number> =
[...BuildArray<A>, ...BuildArray<B>]['length'];
type Five = Add<2, 3>; // 5
This is parlor-trick territory — slow at compile time, brittle. Use sparingly.
Deep readonly:
type DeepReadonly<T> = {
readonly [K in keyof T]:
T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
type Frozen = DeepReadonly<{ a: { b: { c: number } } }>;
// readonly all the way down
Path / type from key path:
type PropType<T, Path extends string> =
Path extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? PropType<T[Key], Rest>
: never
: Path extends keyof T
? T[Path]
: never;
type Nested = { user: { profile: { name: string } } };
type N = PropType<Nested, 'user.profile.name'>; // string
Recursion limit — TypeScript caps recursion at depth ~50 (used to be 25). Hitting it triggers an error. For long lists or deep trees, use iterative approaches.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…