Skip to content
Recursive Conditional Types
step 1/5

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…