How to fix Cannot use conditional type without 'extends' clause in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 8, 2025ยท 84 views

This TypeScript error occurs when you attempt to define a conditional type without using the required 'extends' keyword. Conditional types must follow the syntax 'T extends U ? X : Y' to specify the condition being tested.

Quick fix

Fixes Cannot use conditional type without 'extends' clause

// WRONG - missing 'extends' keyword
type IsString<T> = T string ? true : false;

// CORRECT - proper conditional type syntax
type IsString<T> = T extends string ? true : false;

// Usage
type Test1 = IsString<"hello">; // true
type Test2 = IsString<number>;  // false
  1. Add the extends keyword to your conditional type
  2. Fix infer keyword placement in extends clause
  3. Understand conditional type syntax structure
  4. Handle nested conditional types correctly
typescript โ€” error
// WRONG - missing 'extends' keyword
type IsString<T> = T string ? true : false;
// CORRECT - proper conditional type syntax
type IsString<T> = T extends string ? true : false;
// Usage
type Test1 = IsString<"hello">; // true
type Test2 = IsString<number>; // false
Cannot use conditional type without 'extends' clause

What this error means

TypeScript conditional types are a powerful feature that allow you to create types that change based on a condition, similar to ternary operators in JavaScript. They follow the syntax `T extends U ? X : Y`, where TypeScript checks if type T is assignable to type U, and resolves to type X if true, or type Y if false. This error appears when you try to use conditional type syntax without including the required `extends` keyword. The `extends` clause is mandatory because it defines the actual condition being tested. Without it, TypeScript cannot determine what comparison to make or when to apply the true/false branches. The error is particularly common when working with the `infer` keyword, which is only permitted within the `extends` clause of a conditional type. The `infer` keyword allows you to declare a type variable within the condition and use it in the true branch, but it must appear to the right of the `extends` keyword.

Typical symptoms

  • TypeScript compilation fails with error about conditional types
  • Error message: 'Cannot use conditional type without extends clause'
  • Using ternary-like syntax with ? : in type definitions doesn't work
  • Attempting to use 'infer' keyword outside of an extends clause
  • Type definition with question mark syntax is rejected by compiler
  • IDE shows red underlines when defining conditional types

Common causes

  1. Missing 'extends' keyword in a conditional type definition
  2. Using ternary operator syntax (? :) without the extends condition
  3. Attempting to use 'infer' keyword outside of an extends clause
  4. Incorrect syntax when trying to create type conditionals
  5. Confusing JavaScript ternary syntax with TypeScript conditional types
  6. Incomplete type definition when refactoring or copying code

How to fix "Cannot use conditional type without 'extends' clause"

1Add the extends keyword to your conditional type

Conditional types must use the extends keyword to define what condition is being tested. Fix the syntax by adding extends between your type parameter and the condition:

typescript
// WRONG - missing 'extends' keyword
type IsString<T> = T string ? true : false;

// CORRECT - proper conditional type syntax
type IsString<T> = T extends string ? true : false;

// Usage
type Test1 = IsString<"hello">; // true
type Test2 = IsString<number>;  // false

The basic pattern is always: T extends U ? TrueType : FalseType

2Fix infer keyword placement in extends clause

The infer keyword can only be used within the extends clause of a conditional type. It must appear to the right of the extends keyword:

typescript
// WRONG - infer used without extends
type GetElementType<T> = T (infer U)[] ? U : never;

// CORRECT - infer within extends clause
type GetElementType<T> = T extends (infer U)[] ? U : never;

// Usage: Extract element type from arrays
type StringArray = string[];
type ElementType = GetElementType<StringArray>; // string

// WRONG - infer in the wrong position
type ReturnType<T> = (infer R) T extends (...args: any[]) => any ? R : never;

// CORRECT - infer on the right side of extends
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

The infer keyword declares a type variable that captures part of the matched type.

3Understand conditional type syntax structure

Conditional types follow a specific structure that mirrors JavaScript ternary operators but with type checking:

typescript
// Basic structure: T extends U ? X : Y
type Example<T> = T extends TargetType ? MatchType : NonMatchType;

// Real-world example: Extract function return type
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function greet(): string {
  return "hello";
}

type GreetReturn = GetReturnType<typeof greet>; // string

// Example: Check if type has a name property
type HasName<T> = T extends { name: string } ? true : false;

type Person = { name: string; age: number };
type User = { id: number };

type PersonHasName = HasName<Person>; // true
type UserHasName = HasName<User>;     // false

The extends keyword checks if the type on the left is assignable to the type on the right.

4Handle nested conditional types correctly

When nesting conditional types, each level must have its own extends clause:

typescript
// WRONG - missing extends in nested condition
type Unwrap<T> = T extends Promise<infer U>
  ? U Promise<any> ? Unwrap<U> : U
  : T;

// CORRECT - each condition has extends
type Unwrap<T> = T extends Promise<infer U>
  ? U extends Promise<any> ? Unwrap<U> : U
  : T;

// Usage: Recursively unwrap nested Promises
type SinglePromise = Promise<string>;
type NestedPromise = Promise<Promise<Promise<number>>>;

type Unwrapped1 = Unwrap<SinglePromise>;  // string
type Unwrapped2 = Unwrap<NestedPromise>;  // number

// Another example: Flatten array types
type Flatten<T> = T extends (infer U)[]
  ? U extends any[] ? Flatten<U> : U
  : T;

type NestedArray = string[][][];
type Flattened = Flatten<NestedArray>; // string

Each conditional branch can contain another conditional type with its own extends clause.

5Use proper syntax for distributive conditional types

Conditional types distribute over union types automatically when used with type parameters. This behavior requires correct extends syntax:

typescript
// Distributes over unions automatically
type ToArray<T> = T extends any ? T[] : never;

type StringOrNumber = string | number;
type Result = ToArray<StringOrNumber>; // string[] | number[]

// To prevent distribution, wrap in brackets
type ToArrayNonDistributive<T> = [T] extends [any] ? T[] : never;
type Result2 = ToArrayNonDistributive<StringOrNumber>; // (string | number)[]

// Real example: Filter out null/undefined
type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string

// Example: Extract function types from union
type ExtractFunction<T> = T extends (...args: any[]) => any ? T : never;

type Mixed = string | (() => void) | number | ((x: number) => string);
type OnlyFunctions = ExtractFunction<Mixed>; // (() => void) | ((x: number) => string)

Distribution applies the conditional type to each member of a union separately.

Advanced notes

### Understanding Type Assignability

The extends keyword in conditional types checks assignability, not inheritance. A extends B means "can a value of type A be assigned to a variable of type B?"

typescript
// Structural typing example
type HasId = { id: number };
type User = { id: number; name: string };

type CanAssign = User extends HasId ? true : false; // true
// User has all properties of HasId plus more

### Variance and Conditional Types

Conditional types can create complex variance relationships:

typescript
// Contravariance with function parameters
type GetParam<T> = T extends (param: infer P) => any ? P : never;

type Fn = (x: string) => void;
type Param = GetParam<Fn>; // string

// Multiple infer positions
type GetBoth<T> = T extends (param: infer P) => infer R
  ? { param: P; return: R }
  : never;

type BothTypes = GetBoth<(x: number) => string>;
// { param: number; return: string }

### Conditional Types vs Type Guards

Don't confuse conditional types (compile-time) with type guards (runtime):

typescript
// COMPILE-TIME: Conditional type
type IsString<T> = T extends string ? true : false;

// RUNTIME: Type guard function
function isString(value: unknown): value is string {
  return typeof value === "string";
}

### Template Literal Types with Conditional Types

Combine conditional types with template literals for powerful patterns:

typescript
// Extract method names that start with "get"
type GetterKeys<T> = {
  [K in keyof T]: K extends `get${string}` ? K : never
}[keyof T];

type Example = {
  getName: () => string;
  getAge: () => number;
  setName: (s: string) => void;
  id: number;
};

type Getters = GetterKeys<Example>; // "getName" | "getAge"

### Recursive Conditional Types

TypeScript supports recursive conditional types with depth limits:

typescript
// Deep readonly implementation
type DeepReadonly<T> = T extends object
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
  : T;

type Mutable = {
  user: {
    name: string;
    address: {
      city: string;
    };
  };
};

type Immutable = DeepReadonly<Mutable>;
// All properties at all levels are readonly

Frequently asked questions

What does "Cannot use conditional type without 'extends' clause" mean?
TypeScript conditional types are a powerful feature that allow you to create types that change based on a condition, similar to ternary operators in JavaScript. They follow the syntax T extends U ? X : Y, where TypeScript checks if type T is assignable to type U, and resolves to type X if true, or type Y if false.
How do I fix "Cannot use conditional type without 'extends' clause"?
This TypeScript error occurs when you attempt to define a conditional type without using the required 'extends' keyword. Conditional types must follow the syntax 'T extends U ? X : Y' to specify the condition being tested.
What causes "Cannot use conditional type without 'extends' clause"?
Missing 'extends' keyword in a conditional type definition Using ternary operator syntax (? :) without the extends condition Attempting to use 'infer' keyword outside of an extends clause
Is the "Cannot use conditional type without 'extends' clause" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading