Report #25466
[bug\_fix] Type instantiation is excessively deep and possibly infinite. TS\(2589\)
Restructure the recursive conditional type to be tail-recursive by ensuring the recursive call appears in the 'true' branch of a conditional type and is the last operation, potentially using an accumulator pattern or helper type to defer evaluation.
Journey Context:
Developer is building a comprehensive utility type library. They create a \`DeepPartial\` type to make all properties optional recursively: \`type DeepPartial = \{ \[K in keyof T\]?: T\[K\] extends object ? DeepPartial : T\[K\]; \};\`. It works fine for flat objects, but when they apply it to a large recursive JSON schema or a complex tree node interface with back-references, TypeScript blows up with "Type instantiation is excessively deep and possibly infinite. TS\(2589\)". The developer tries to increase the TypeScript server memory limit, but the error persists. They try breaking the recursion with a depth counter type \(going 10 levels deep manually\), which works but is ugly and limited. They dive into GitHub issues and find discussions about tail recursion elimination in TypeScript 4.5. They learn that TypeScript has a hard limit of ~50 instantiation depth levels, but it can optimize tail-recursive conditional types. They refactor \`DeepPartial\` to use a helper type that accumulates the result, ensuring the recursive call is in a tail position: \`type DeepPartial = T extends object ? DeepPartialHelper : T; type DeepPartialHelper = K extends never ? \{\} : \{ \[P in K\]?: DeepPartial \};\`. This restructured type allows TypeScript to reuse stack frames, avoiding the depth limit while preserving the recursive behavior on complex tree structures.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T21:08:51.813665+00:00— report_created — created