What is a "conditional type"?
What a Conditional Type is
A Conditional Type has the general form:
javascript
T extends U ? X : YThis reads as:
"If type
Tis assignable to typeU, then the result is typeX, otherwise it is typeY."
The simplest example
javascript
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"How it works
extendsin the context of a conditional type is not "inheritance" but a type compatibility check;- the condition is evaluated at compile time;
- the result is another type.
Example with real types
javascript
type ElementType<T> = T extends (infer U)[] ? U : T;
type A = ElementType<string[]>; // string
type B = ElementType<number[]>; // number
type C = ElementType<boolean>; // booleanThis uses
infer U, an operator for extracting a subtype.
Using it with generics
Conditional types are especially powerful in generics:
javascript
type Response<T> = T extends Error ? "Failed" : "Success";
type A = Response<string>; // "Success"
type B = Response<Error>; // "Failed"Example: filtering types
javascript
type NonNullable<T> = T extends null | undefined ? never : T;
type A = NonNullable<string | null | undefined>; // stringThis is the actual implementation of the built-in
NonNullable.
Distributive behavior
Conditional types behave differently when T is a union.
If T is a union (A | B), TypeScript distributes the condition over each member:
javascript
type ToArray<T> = T extends any ? T[] : never;
type R = ToArray<string | number>;
// (string | number) distributes -> string[] | number[]That is:
javascript
ToArray<string | number> ≡ ToArray<string> | ToArray<number>This is called a distributive conditional type.
To turn off distribution
You can wrap the type in a tuple to "remove" the distributivity:
javascript
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type R = ToArrayNonDist<string | number>;
// (string | number)[]Examples from the standard library
Many built-in utilities are built on conditional types:
| Utility | Implementation | What it does |
|---|---|---|
Exclude<T, U> | T extends U ? never : T | Removes from T everything assignable to U |
Extract<T, U> | T extends U ? T : never | Keeps only the intersection of T and U |
NonNullable<T> | T extends null | undefined ? never : T | Removes null and undefined |
ReturnType<T> | T extends (...args:any) => infer R ? R : any | Extracts the return value's type |
InstanceType<T> | T extends new (...args:any) => infer R ? R : any | Extracts the type of the created instance |
Practical examples
Choosing the return type
javascript
type Result<T> = T extends true ? "OK" : "FAIL";
type A = Result<true>; // "OK"
type B = Result<false>; // "FAIL"Checking whether a type is a function
javascript
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
type A = IsFunction<() => void>; // true
type B = IsFunction<number>; // falseExtracting a Promise's result
javascript
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type A = UnwrapPromise<Promise<string>>; // string
type B = UnwrapPromise<number>; // numberConditional typing of parameters
javascript
type ApiResponse<T> = T extends { error: any }
? { ok: false; error: T["error"] }
: { ok: true; data: T };
type A = ApiResponse<{ data: string }>; // { ok: true; data: { data: string } }
type B = ApiResponse<{ error: string }>; // { ok: false; error: string }Key concepts
| Term | Explanation |
|---|---|
extends | Checks type compatibility |
infer | Lets you extract nested types |
| Distributivity | The conditional type is applied separately to each member of a union |
never | Used to "exclude" values from a union |
| "Type-level if" | Conditional types are a way to describe branching logic at the type level |
Summary
| Concept | Description |
|---|---|
| Conditional type | A type that is chosen depending on another type |
| Syntax | T extends U ? X : Y |
| When to use | When a type depends on the shape/compatibility of another type |
| Key tools | extends, infer, never |
| Examples | Exclude, Extract, ReturnType, NonNullable, InstanceType |
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.