This error occurs when you try to reference a type variable inside the constraint portion of a conditional type. TypeScript doesn't allow using inferred type variables or parameters in the extends clause because constraints are evaluated before inference happens. The fix involves restructuring your type to reference the variable in the branches instead of the constraint.
Conditional types in TypeScript use the syntax `T extends Condition ? TrueType : FalseType` to select different types based on patterns. The error 'Conditional type cannot reference type variable in constraint' occurs when you attempt to reference a type variable (typically one being inferred) inside the extends clause itself. This happens because: - The constraint portion of a conditional type is evaluated before the type body - Type variables captured with `infer` can only be used in the branches, not in constraints - Constraints define what types are allowed, while branches use those inferred types - TypeScript's type resolution order doesn't permit referencing inferred variables in their own constraint
The constraint portion of a conditional type (after extends) is evaluated first and cannot reference inferred types. Only the true and false branches can use inferred variables.
Wrong - constraint tries to reference inferred type:
type Wrong<T> = T extends (infer U extends string)[] ? U : never;
// Error: Cannot reference inferred type in constraintCorrect - reference inferred type in branch:
type Correct<T> = T extends (infer U)[] ? (U extends string ? U : never) : never;The key difference: the constraint checks if T is an array, then the branch checks if U (the inferred element type) is a string.
If you need to constrain a type variable, apply the constraint to the generic type parameter itself, not in the conditional clause.
Problem:
type ExtractString<T> = T extends (infer Item extends string)[] ? Item : never;
// Error: Cannot reference inferred type in constraintSolution - constrain the outer parameter:
type ExtractString<T extends string[]> = T extends (infer Item)[] ? Item : never;Or use the constraint in TypeScript 5+ style:
type ExtractString<T> = T extends (infer Item)[]
? (Item extends string ? Item : never)
: never;When you need to both infer and constrain a type, use nested conditionals where the inner conditional checks the constraint.
Problem:
type GetProperty<T, K> = T extends Record<K extends string ? K : never, infer V> ? V : never;
// Error: Cannot use constraint with inferred typeSolution - nested conditionals:
type GetProperty<T, K> = K extends string
? K extends keyof T
? T[K]
: never
: never;This first checks if K is a string, then checks if it's a key of T, avoiding the constraint reference problem.
Refactor your conditional type to infer the variable first at the top level, then apply constraints in the branches.
Problem:
type Unwrap<T> = T extends Promise<infer U extends { id: string }> ? U : T;
// Error: Cannot reference inferred type in constraintSolution - separate inference from constraint:
type Unwrap<T> = T extends Promise<infer U>
? (U extends { id: string } ? U : never)
: T;The key is: infer U without constraints, then check the constraint in the branch.
TypeScript 5.4 introduced support for constraints on inferred types, but with specific syntax. Ensure you're using the correct syntax for your version.
TypeScript 5.4+ correct syntax:
// This syntax IS allowed in 5.4+ when properly structured
type GetString<T> = T extends (...args: any[]) => (infer R extends string)
? R
: never;However, this only works in specific contexts (like function return types). For array element inference, use the nested approach:
type GetStringElement<T> = T extends (infer E)[]
? E extends string ? E : never
: never;Check your tsconfig.json for the compilerOptions.target or compilerOptions.lib to ensure you're on TypeScript 5.4+.
If your conditional type is complex, create intermediate helper types to handle inference and constraints separately.
Problem:
type Complex<T> = T extends {
data: (infer Items extends { id: string })[]
} ? Items : never;
// Error: Cannot reference inferred type in constraintSolution - split into helper types:
// First helper: extract the array
type ExtractDataArray<T> = T extends { data: infer D } ? D : never;
// Second helper: extract array elements
type ArrayElements<T> = T extends (infer E)[] ? E : never;
// Third helper: check if has id
type HasId<T> = T extends { id: string } ? T : never;
// Compose them
type Complex<T> = HasId<ArrayElements<ExtractDataArray<T>>>;This approach is clearer and avoids the constraint reference error.
### Why This Limitation Exists
TypeScript evaluates conditional types in this order:
1. Constraint evaluation: Check if T extends the constraint
2. Inference: If matched, capture inferred types using infer
3. Branch selection: Choose true or false branch based on match
4. Branch evaluation: Evaluate the selected branch with inferred types
Since constraints are evaluated in step 1 before inference happens in step 2, inferred variables don't exist yet when constraints are being checked. This is a fundamental limitation of TypeScript's type evaluation model.
### Type Inference Precedence
When TypeScript sees a conditional type, it follows this precedence:
1. Type parameters must be fully defined or inferrable from context
2. Constraints apply to type parameters (not inferred types)
3. Inferred types are captured during constraint matching
4. Branches can use both original parameters and inferred types
### Working Patterns
Extracting from a discriminated union:
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;Extracting function parameters:
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;Extracting Promise type:
type Awaited<T> = T extends Promise<infer U> ? U : T;All these work because the constraint is on the outer parameter T, not on the inferred type.
### Related Errors
- "Type 'U' does not satisfy the constraint": Check if U is constrained in the correct scope
- "Inferred type cannot reference itself": Avoid recursive references in inferred types
- "Type parameter is not known to satisfy constraint": Ensure the parameter type matches the constraint
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript