Conditional Types
Learn how to choose between two types based on a condition, using TypeScript’s extends ? : syntax.
Reading Time
18 min
Lesson
Lesson 24 of 30
What is a Conditional Type?
A conditional type picks between two types based on whether one type is assignable to another, using syntax that mirrors JavaScript’s ternary operator: T extends U ? X : Y.
A Basic Conditional Type
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"A More Practical Example
Conditional types are most useful when combined with generics, letting a type adapt its shape based on what it’s given.
Flattening a Possibly-Array Type
type Flatten<T> = T extends (infer Item)[] ? Item : T;
type A = Flatten<string[]>; // string
type B = Flatten<number>; // number (unchanged, since it isn't an array)The infer Keyword
infer introduces a new type variable inside the extends clause, letting TypeScript extract and capture a piece of a type — like the element type of an array, or a function’s return type.
Extracting a Return Type with infer
type MyReturnType<F> = F extends (...args: any[]) => infer R ? R : never;
function greet() {
return "hello";
}
type Result = MyReturnType<typeof greet>; // stringDistributive Conditional Types
When a conditional type is applied to a union, it automatically distributes over each member of the union individually, then combines the results back into a union.
Distribution Over a Union
type ToArray<T> = T extends any ? T[] : never;
type Result = ToArray<string | number>;
// Distributes to: string[] | number[] (not (string | number)[])Chaining Conditional Types
Multiple conditional types can be chained together to express more complex, multi-branch logic entirely at the type level.
Chained Conditional Type
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
"object";
type A = TypeName<42>; // "number"
type B = TypeName<true>; // "boolean"This is Advanced, Library-Level TypeScript
Conditional types (especially combined with infer) are mostly seen in library and utility-type code, not everyday application code — but recognizing the pattern helps when reading type errors from libraries you depend on.
Best Practice
Reach for conditional types when building reusable, generic utilities. In application code, prefer simpler, explicit types wherever possible — conditional types can quickly become hard to read.