Report #73602
[bug\_fix] Type instantiation is excessively deep and possibly infinite. ts\(2589\)
Refactor the recursive type to use tail-recursion elimination \(available in TypeScript 4.5\+\), which requires restructuring conditional types so that the recursive call is in the final \(else\) branch and accumulates in a type parameter. Alternatively, introduce an explicit depth limit counter \(e.g., \`Depth extends number = 10\`\) that decrements on each recursion, stopping at 0 to prevent infinite instantiation. Root cause: TypeScript imposes a depth limit \(typically ~50 instantiations\) on recursive type evaluation to prevent infinite loops during type checking. Complex utility types like \`DeepPartial\`, \`DeepReadonly\`, or tuple manipulation utilities that recurse deeply on large or circular object structures exceed this limit.
Journey Context:
You create a utility type \`DeepReadonly\` to freeze nested configuration objects: \`type DeepReadonly = \{ readonly \[K in keyof T\]: DeepReadonly; \}\`. It works fine on small configs. You apply it to a massive auto-generated GraphQL schema type that has deeply nested input types \(10\+ levels deep\). Suddenly, TypeScript reports 'Type instantiation is excessively deep and possibly infinite' on the line where you use \`DeepReadonly\`. You inspect the type and see circular references \(e.g., \`type Node = \{ children: Node\[\] \}\`\). You search the error and find GitHub issue \#30188 explaining the depth limit. You try to increase it but find it's hardcoded. You read the TypeScript 4.5 release notes about Tail Recursion Elimination on Conditional Types. You refactor \`DeepReadonly\` into a tail-recursive form using an accumulator and conditional types with \`infer\`. You define a helper that checks if the type is an object, and if so, maps over keys recursively, but ensures the recursion happens in the 'else' branch of a conditional type with an accumulator. After refactoring, the type resolves instantly even on the deep GraphQL schema. Alternatively, where tail recursion is complex, you add a depth counter \`Depth extends number = 5\` and decrement it using a \`Prev\` type, returning \`T\` when \`Depth\` reaches 0, effectively limiting recursion artificially.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T06:08:23.993700+00:00— report_created — created