Conditional types are a feature of the TypeScript language that allow for the creation of types that depend on the evaluation of other types. They are created using the extends
keyword to define a type based on a conditional check.
They have the following syntax:
Type extends Condition ? TrueType : FalseType
This means that if Type
is assignable to Condition
, then the conditional type evaluates to TrueType
; otherwise, it evaluates to FalseType
.
For example, suppose we have the following types:
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
We can use a conditional type to create a new type that depends on whether a type is a subtype of Animal or not:
type Example1 = Dog extends Animal ? number : string; // number
type Example2 = RegExp extends Animal ? number : string; // string
Conditional types are especially useful when combined with generics, because they can express complex type transformations based on generic parameters. For example, suppose we have a function that creates labels for different types of objects:
interface IdLabel {
id: number; // some fields
}
interface NameLabel {
name: string; // other fields
}
function createLabel<T>(idOrName: T): T extends number ? IdLabel : NameLabel {
// implementation
}
This function uses a conditional type to return different types of labels based on whether the input is a number or a string. If we call it with a number, we get an IdLabel; if we call it with a string, we get a NameLabel:
let a = createLabel("typescript"); // NameLabel
let b = createLabel(2.8); // IdLabel
let c = createLabel(Math.random() ? "hello" : 42); // NameLabel | IdLabel
Conditional types can also be distributive over union types, which means that they apply to each member of the union separately and produce a new union type. For example, suppose we have the following type:
type Pet = Dog | Cat;
We can use a conditional type to create a new type that maps each Pet to its sound:
type PetSound<T> = T extends Dog ? "woof" : "meow";
type Sound = PetSound<Pet>; // "woof" | "meow"
Conditional types can also be nested, recursive, and inferential.