How to fix Type instantiation is excessively deep and possibly infinite in TypeScript
TypeScript throws this error when type recursion or nesting exceeds internal depth limits (50-500 instantiations). This commonly happens with deeply nested generic types, recursive type definitions, or complex type compositions.
Quick fix
Fixes TS2589
// tsconfig.json
{
"compilerOptions": {
"extendedDiagnostics": true
}
}- Identify the problematic type using compiler diagnostics
- Add explicit type annotations to break inference chains
- Simplify recursive types with depth limits
- Use type deferral with object properties
// tsconfig.json{"compilerOptions": {"extendedDiagnostics": true}}Type instantiation is excessively deep and possibly infinite
What this error means
This error occurs when TypeScript's type checker encounters type definitions that are too deeply nested or potentially infinitely recursive. TypeScript imposes depth limits to prevent infinite loops and protect compiler performance. The compiler tracks how many times it needs to "instantiate" (resolve) a type during type checking. When this count exceeds the limit (increased from 50 to 500 in TypeScript 4.1+), the error is thrown. This is a safety mechanism to prevent stack overflows and keep the language server responsive. Common triggers include recursive conditional types, deeply composed generic types (like Redux selectors or Zod schemas), complex mapped types, and intricate type intersections. The error often appears after TypeScript version upgrades as the compiler becomes stricter or type definitions in dependencies become more sophisticated.
Typical symptoms
- Error "TS2589: Type instantiation is excessively deep and possibly infinite" appears in IDE or during build
- Error occurs only in large codebases but not in TypeScript Playground with isolated code
- Type checking becomes extremely slow before the error appears
- Error appears after upgrading TypeScript or updating type-heavy dependencies (Redux, Zod, i18next, etc.)
- Styled components or other library wrappers show type errors that were previously fine
- Error message points to deeply nested generic types or recursive type definitions
Common causes
- Recursive conditional types without proper termination conditions or depth controls
- Deeply nested type compositions (7+ levels deep) such as selectors calling selectors calling selectors
- Complex generic types in libraries (React, Redux, Zod, i18next) interacting with your code
- Styled components or HOCs wrapping components multiple times without explicit type annotations
- Large union types combined with mapped types or complex conditional types
- Circular type references where types reference each other without base cases
- TypeScript version upgrade exposing previously undetected type complexity
How to fix "Type instantiation is excessively deep and possibly infinite"
The error message usually points to the file and type causing the issue. Enable verbose compiler output:
// tsconfig.json
{
"compilerOptions": {
"extendedDiagnostics": true
}
}Look for the specific type or file mentioned in the error. If the error is vague, comment out recent changes or dependencies to isolate the source.
TypeScript infers types through potentially deep chains. Break these with explicit annotations:
// Before: TypeScript infers through multiple levels
const StyledButton = styled(Button);
// After: Explicit type stops deep inference
const StyledButton = styled(Button) as typeof Button;
// For function compositions
const selector = createSelector(
inputSelector,
(state) => state.data
) as (state: RootState) => DataType;This tells TypeScript to use the simpler asserted type rather than computing a complex inferred type.
Add a depth parameter to prevent infinite recursion:
// Before: Potentially infinite recursion
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// After: Depth-limited version
type DeepPartial<T, D extends number = 5> = D extends 0
? T
: {
[P in keyof T]?: T[P] extends object
? DeepPartial<T[P], Prev[D]>
: T[P];
};
type Prev = [never, 0, 1, 2, 3, 4, 5, ...0[]];The depth limit prevents TypeScript from recursing too deeply.
Wrapping recursive references in object properties or arrays defers instantiation:
// Before: Immediate instantiation
type Tree<T> = T | Tree<T>[];
// After: Deferred instantiation
type Tree<T> = T | { children: Tree<T>[] };This works because TypeScript doesn't immediately instantiate types inside object properties, reducing the instantiation depth.
If the error comes from node_modules type definitions:
// tsconfig.json
{
"compilerOptions": {
"skipLibCheck": true
}
}This skips type checking of declaration files (.d.ts) in node_modules. This is a workaround, not a fix, but can unblock builds while waiting for library updates.
Warning: This may hide legitimate type errors in dependencies.
TypeScript 4.5+ includes tail-recursion optimization for conditional types:
npm install typescript@latest --save-devAlso update type-heavy dependencies:
npm update @types/react @reduxjs/toolkit zodNewer versions often include type optimizations that reduce instantiation depth. Check release notes for "type instantiation" or "recursion depth" fixes.
Advanced notes
Tail Recursion Optimization: TypeScript 4.5+ performs tail-recursion elimination on conditional types. If one branch of a conditional type is simply another conditional type, TypeScript avoids intermediate instantiations:
type InfiniteLoop<T> = T extends string ? InfiniteLoop<T> : never;
// TypeScript 4.5+ optimizes this tail-recursive patternIntersection Type Counter Reset: Using intersection types can reset TypeScript's internal counter, extending limits:
type DeepType<T> = T & { /* properties */ };
// The intersection resets the instantiation counterCompiler Internals: The limit exists because resolution of recursive types causes deeply nested invocations in the instantiateType function, risking stack overflows. The limit was 50 in TypeScript 4.0, increased to 500 in 4.1 via PR #45025.
Library-Specific Issues: Some libraries are particularly prone to this error:
- Redux Toolkit: Deep selector composition with createSelector
- Zod: Recursive schema definitions with .lazy()
- i18next: Complex translation key type generation
- Kysely: Type-safe query builders with deep joins
For these, consult library-specific documentation (e.g., Kysely's "Dealing with excessively deep types" guide).
Frequently asked questions
- What does "TS2589" mean?
- This error occurs when TypeScript's type checker encounters type definitions that are too deeply nested or potentially infinitely recursive. TypeScript imposes depth limits to prevent infinite loops and protect compiler performance. The compiler tracks how many times it needs to "instantiate" (resolve) a type during type checking.
- How do I fix "TS2589"?
- TypeScript throws this error when type recursion or nesting exceeds internal depth limits (50-500 instantiations). This commonly happens with deeply nested generic types, recursive type definitions, or complex type compositions.
- What causes "TS2589"?
- Recursive conditional types without proper termination conditions or depth controls Deeply nested type compositions (7+ levels deep) such as selectors calling selectors calling selectors Complex generic types in libraries (React, Redux, Zod, i18next) interacting with your code
- Is the "TS2589" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐TypeScript Official Documentation
- ๐Github.com - 45025(GitHub)
- ๐Github.com - 34933(GitHub)
- ๐Kysely.dev - excessively-deep-types(Official Docs)
- ๐
- ๐Github.com - 534(GitHub)
- ๐