Report #87273
[bug\_fix] TS2589: Type instantiation is excessively deep and possibly infinite. OR TS2321: Excessive stack depth comparing types 'X' and 'Y'.
Refactor recursive conditional types to include a termination condition that catches primitives \(e.g., \`T extends object ? ... : T\`\) to prevent infinite recursion, or use TypeScript 4.5\+ tail-recursion elimination patterns with accumulator parameters.
Journey Context:
Developer attempts to create a powerful utility type that deeply modifies an interface, such as making all properties optional recursively: \`type DeepPartial = \{ \[K in keyof T\]?: DeepPartial \};\`. They apply this to a large, complex auto-generated type from an ORM \(like Prisma Client\) or a massive API schema. Suddenly, the TypeScript language server crashes or hangs indefinitely, eventually throwing "Type instantiation is excessively deep and possibly infinite". The developer initially suspects a bug in TypeScript and considers downgrading. They examine the type definition and realize that for primitive types like \`string\`, the mapped type \`\{ \[K in keyof string\]?: ... \}\` iterates over String prototype methods like \`charAt\`, \`slice\`, etc., creating an infinitely expanding type tree. The "aha" moment comes from studying utility libraries like \`type-fest\`: they need to add a conditional check to stop recursion when \`T\` is no longer an object \(i.e., it's a primitive\). The fix is to change the type to \`type DeepPartial = T extends object ? \{ \[K in keyof T\]?: DeepPartial \} : T;\`. This ensures that when \`T\` is \`string\`, \`number\`, etc., it returns \`T\` immediately without recursion, preventing the stack overflow. For TypeScript 4.5\+, they also learn about tail-recursion elimination for complex accumulators, but the base case check is the immediate fix.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T05:04:33.577233+00:00— report_created — created