Suggest an editImprove this articleRefine the answer for “What is a "conditional type"?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A **conditional type** has the general form `T extends U ? X : Y`: if type `T` is **assignable** to type `U`, the result is type `X`, otherwise it is type `Y`. **Key point:** the condition is evaluated **at compile time**, and the result is **another type**, not a value.Shown above the full answer for quick recall.Answer (EN)Image## What a Conditional Type is A **Conditional Type** has the general form: ```javascript T extends U ? X : Y ``` This reads as: > "If type `T` is **assignable** to type `U`, > then the result is type `X`, otherwise it is type `Y`." --- ### 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 - `extends` in 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>; // boolean ``` > This 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>; // string ``` > This 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>; // false ``` --- ### Extracting 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>; // number ``` --- ### Conditional 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` |For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.