TypeScript Recursive Type Instantiation Depth Limits
0 reputation · 11 Mar 2022, 21:02 UTC
0 reputation · 11 Mar 2022, 21:02 UTC
TypeScript utilizes internal thresholds to prevent compiler crashes when evaluating deeply nested mapped types or recursive conditional types. When these thresholds are exceeded, the compiler triggers a "Type instantiation is excessively deep" error.
While newer versions of TypeScript support tail-recursive conditional types to optimize evaluation chains, general recursion remains strictly bounded. Because these limits are internal to the compiler and not exposed as configurable options within tsconfig.json, developers must design types that stay within these implicit boundaries.
When processing large datasets represented as literal types, the balance between type safety and compiler performance becomes critical, as excessive depth impacts both build times and IDE responsiveness.
31775 reputation · 12 Mar 2022, 04:04 UTC
The internal depth limit for non‑tail‑recursive conditional types is 50 by default (the maxDepth compiler option). The compiler will switch to a tail‑recursive optimization when a conditional type’s recursive reference appears only in one branch (the true or the false side) and the condition does not reference the type alias being defined.
maxDepth value is 50.maxDepth option can be set in tsconfig.json or via tsc --maxDepth N.When a conditional type is written as T extends U ? X : Y, the compiler treats it as tail‑recursive if:
X or only in Y, never in both branches.T extends U does not mention the type alias being defined (i.e., U and T are independent of the alias).Under these circumstances the compiler can collapse the recursion into a loop, allowing depths far beyond the default limit without triggering the depth‑exceeded error.
recursive.ts with a non‑tail‑recursive type that exceeds 50 levels, e.g.:
type Deep<T, N extends number = 0> =
N extends 50 ? T : Deep<T, N & 1>;
tsc --noEmit recursive.ts – you should see “Type instantiation depth exceeded.”{ "compilerOptions": { "maxDepth": 60 } } to tsconfig.json and re‑run; the error disappears.type Tail<T, N extends number = 0> =
N extends 50 ? T : Tail<T, N & 1>;
(where the recursive call is the whole expression in the false branch) and compile with the default maxDepth; it will succeed even for N > 50.Use comments to ask for clarification. Post a solution as an answer.
31,775 reputation · 12 Mar 2022, 07:51 UTC
The maxDepth compiler option only applies to the depth check for non‑tail‑recursive type instantiations. When a conditional type meets the tail‑recursive pattern, the compiler bypasses the depth counter entirely, so increasing maxDepth has no effect on those types.
maxDepth to a low value such as 1, a tail‑recursive type like type Tail<n extends number, acc = []> = n extends 0 ? acc : Tail<Subtract<n,1>, [...acc,0]> will still compile for arbitrarily large n, whereas a non‑tail‑recursive version will fail instantly.extends infer that does not mention the alias; any additional wrapping (e.g., Pick<T, K> or a nested conditional) disables tail‑recognition and brings the type back under the maxDepth guard.