How to fix Cannot infer type variable 'T' in conditional type in TypeScript
This error occurs when TypeScript's type inference cannot determine the type of a variable within a conditional type clause. The fix typically involves providing explicit type hints or restructuring the conditional type to give TypeScript enough information to infer the type.
Quick fix
Fixes Cannot infer type variable 'T' in conditional type
type ExtractArrayElement<T> = T extends any[] ? string : T[]; // Error: T doesn't exist in false branch- Understand the infer keyword scope
- Ensure the condition pattern matches the type
- Check for union type distribution
- Add explicit type hints to generic parameters
type ExtractArrayElement<T> = T extends any[] ? string : T[]; // Error: T doesn't exist in false branchCannot infer type variable 'T' in conditional type
What this error means
Conditional types in TypeScript use the syntax `T extends Condition ? TrueType : FalseType` to select different types based on whether T matches a condition. When you use the `infer` keyword to capture types within the condition, TypeScript must match and extract the type variable. This error occurs when TypeScript cannot determine what type to infer in the condition branch. This happens because: - The type structure doesn't provide enough information for pattern matching - The inferred type appears in the false branch (where it's not allowed) - The generic type parameter isn't constrained enough - The conditional type is applied in a context where TypeScript can't deduce the type
Typical symptoms
- TypeScript compiler error: 'Cannot infer type variable T in conditional type'
- Error appears when defining or using a conditional type with infer
- The error points to a line with extends and infer keywords
- Generic functions with conditional return types fail to compile
- Type inference works in some contexts but not others
Common causes
- Using inferred type variable in the false branch (only allowed in true branch)
- Generic type parameter lacks sufficient structure for pattern matching
- Conditional type applied in a way that doesn't provide enough type information
- Complex nested conditional types without explicit constraints
- Trying to infer from a type that doesn't match the pattern
How to fix "Cannot infer type variable 'T' in conditional type"
The infer keyword can only be used in the true branch of a conditional type. Inferred type variables are not available in the false branch.
Wrong:
type ExtractArrayElement<T> = T extends any[] ? string : T[]; // Error: T doesn't exist in false branchCorrect:
type ExtractArrayElement<T> = T extends (infer E)[] ? E : T;The inferred type E is only available in the true branch (E), not in the false branch (T).
The pattern in the extends clause must match the structure of T for inference to work. Make sure the pattern is complete.
Problem:
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
const result: GetReturnType<string>; // Error: string doesn't match function patternFix: Add a constraint or provide the right type:
type GetReturnType<T extends (...args: any[]) => any> = T extends (...args: any[]) => infer R ? R : never;
const result: GetReturnType<() => string>; // OKThe constraint extends (...args: any[]) => any ensures T is always a function, so inference will work.
When using conditional types with union types, they distribute over each union member. This can affect inference.
Example:
type ToArray<T> = T extends any ? T[] : never;
type A = ToArray<string | number>; // (string | number)[] | (string | number)[] = string[] | number[]If you don't want distribution, wrap the generic in brackets:
type ToArray<T> = [T] extends [any] ? T[] : never;
type B = ToArray<string | number>; // (string | number)[]If TypeScript can't infer the type from usage, provide explicit type arguments:
Problem:
function processArray<T>(arr: T[]): T extends any[] ? 'nested' : 'flat' {
// Error: T is not inferred from the parameter
return 'flat' as any;
}
const result = processArray([1, 2, 3]); // Type of T is ambiguousFix: Use explicit type argument:
const result = processArray<number>([1, 2, 3]); // OKOr restructure to make inference work automatically:
function processArray<T extends any[]>(arr: T): T extends (infer E)[] ? 'nested' : 'flat' {
return (E extends any[] ? 'nested' : 'flat') as any;
}
const result = processArray([1, 2, 3]); // Inference worksDeeply nested conditional types can confuse TypeScript's inference. Break them into smaller, reusable types:
Problem:
type Complex<T> = T extends any[]
? T extends (infer E)[]
? E extends string
? infer U // Error: U not properly inferred in context
: never
: never
: never;Fix: Split into helper types:
type IsArray<T> = T extends any[] ? true : false;
type ArrayElement<T extends any[]> = T extends (infer E)[] ? E : never;
type IsString<T> = T extends string ? true : false;
type Simplified<T> = IsArray<T> extends true
? IsString<ArrayElement<T>> extends true
? ArrayElement<T>
: never
: never;This is clearer and gives TypeScript better opportunities to infer types.
TypeScript 5.0+ allows constraints on inferred type parameters for more precise inference:
Modern approach (TypeScript 5+):
type ExtractStringArrayElement<T extends string[]> = T extends (infer E extends string)[] ? E : never;
const result = ExtractStringArrayElement<['a', 'b']>; // 'a' | 'b'This constraint infer E extends string tells TypeScript that E must be a string, improving inference accuracy.
Advanced notes
### Type Inference Algorithm
TypeScript's conditional type inference uses a pattern-matching algorithm:
1. Compare T against the extends condition
2. If T matches, capture any inferred types using infer
3. Use captured types in the true branch
4. If no match, use false branch
If TypeScript can't confidently determine the match (e.g., T is too generic), inference fails.
### Common Patterns That Work
Extracting Array Elements:
type ArrayElement<T> = T extends (infer E)[] ? E : T;Extracting Function Return Type:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;Extracting Promise Value:
type Awaited<T> = T extends Promise<infer U> ? U : T;### When Inference Fails
Inference often fails when:
- The generic isn't directly used in a way that constrains its structure (e.g., passed as-is to a function)
- You're trying to infer from an unstructured type like unknown or a bare generic
- The conditional type is deferred (TypeScript doesn't evaluate it immediately)
### TypeScript Versions
This error has been present since conditional types were introduced (TypeScript 2.8). Some inference improvements were made in TypeScript 4.7+ with better handling of type inference in nested contexts.
Refer to the TypeScript release notes for version-specific improvements.
Frequently asked questions
- What does "Cannot infer type variable 'T' in conditional type" mean?
- Conditional types in TypeScript use the syntax T extends Condition ? TrueType : FalseType to select different types based on whether T matches a condition. When you use the infer keyword to capture types within the condition, TypeScript must match and extract the type variable.
- How do I fix "Cannot infer type variable 'T' in conditional type"?
- This error occurs when TypeScript's type inference cannot determine the type of a variable within a conditional type clause. The fix typically involves providing explicit type hints or restructuring the conditional type to give TypeScript enough information to infer the type.
- What causes "Cannot infer type variable 'T' in conditional type"?
- Using inferred type variable in the false branch (only allowed in true branch) Generic type parameter lacks sufficient structure for pattern matching Conditional type applied in a way that doesn't provide enough type information
- Is the "Cannot infer type variable 'T' in conditional type" 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
- ๐TypeScript Handbook - Conditional Types(Official Docs)
- ๐TypeScript Handbook - Inferring Within Conditional Types(Official Docs)
- ๐TypeScript 2.8 Release Notes - Conditional Types(Official Docs)
- ๐
- ๐