Report #11432
[bug\_fix] Type instantiation is excessively deep and possibly infinite when using recursive utility types
TypeScript has a hard recursion depth limit \(default 50\) to prevent infinite loops. Deeply recursive mapped types \(like \`DeepPartial\`\) on complex or circular interfaces exceed this. To fix, implement a depth-limiting pattern using a tuple type as a counter. Define a \`DepthLimit\` tuple like \`type DepthCounter = \[never, 0, 1, 2, 3, 4, 5\];\` and pass it down recursively, decrementing the index. When the index reaches 0 \(or \`never\`\), return the original type \`T\` instead of recursing further. This caps the recursion at a safe level while preserving the utility for reasonably nested objects.
Journey Context:
A developer is building a generic form library. They define a type to make all nested properties optional for partial updates: \`type DeepPartial = \{ \[P in keyof T\]?: DeepPartial \};\`. Initially, it works on simple objects. Then they apply it to a complex GraphQL response type that has recursive references \(e.g., a Comment type that contains \`replies: Comment\[\]\`\). Suddenly, the IDE hangs, and TypeScript reports "Type instantiation is excessively deep and possibly infinite." The developer tries to add a conditional \`T extends object ? ... : T\` to stop at primitives, but the error persists because the recursion depth is still too high for the circular reference. They research and find GitHub issues discussing the hard limit. They learn about the "depth counter" hack using tuples. They refactor their type to \`type DeepPartial = D extends never ? T : T extends object ? \{ \[K in keyof T\]?: DeepPartial \} : T;\` where \`Prev\` maps 3->2, 2->1, 1->0, 0->never. The error vanishes, and types resolve instantly.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T13:18:39.713388+00:00— report_created — created