TypeScriptGenerics and advanced types
Conditional types
Types chosen based on a condition: T extends U ? X : Y.
Example
#TypeScript
type Label<T> = T extends string ? 'text' : T extends number ? 'number' : 'something else'
type A = Label<'html'>
// type A = "text"
type B = Label<42>
// type B = "number"
type C = Label<boolean>
// type C = "something else"
type OnlyStrings<T> = T extends string ? T : never
type Mixed = OnlyStrings<'a' | 1 | 'b' | true>
// type Mixed = "a" | "b"Definition and usage
#A conditional type works like the ternary operator, but on types: T extends string ? "text" : "other". If T is assignable to string, the result is the first type, otherwise the second.
When T is a union, the condition is applied to each of its members separately (this is called distribution). This makes it easy to filter unwanted types out of a union by returning never for them. That’s how the built-in Exclude and Extract work.
Conditional types are the foundation of many utility types and libraries. They show up less often in application code, but it’s worth understanding them in order to read type definitions.
Syntax
#Syntax
type Result<T> = T extends Condition ? TypeIfTrue : TypeIfFalseMore examples
#TypeScript
function parse<T extends 'number' | 'boolean'>(value: string, as: T): T extends 'number' ? number : boolean {
return (as === 'number' ? Number(value) : value === 'true') as T extends 'number' ? number : boolean
}
console.log(parse('42', 'number') + 1)
console.log(parse('true', 'boolean'))Result
43 true
Good practices
#- If a conditional type starts getting long, break it up into several named helper types.
- Distribution over a union can be turned off by wrapping the type in square brackets:
[T] extends [string].
Related entries
#- inferPulls a type out from inside another type, within a conditional type.
- Exclude<UnionType, ExcludedMembers>Removes from a union the types that match a given type.
- Extract<Type, Union>Keeps in a union only the types that match a given type.
- neverThe type of a value that never occurs: functions that don’t end normally, and impossible cases.
- Mapped typesCreate a new object type by transforming every key of another type.
Spotted a mistake or missing an example? Write to us.