
Conditional types
Conditional mapped types are an advanced feature introduced in TypeScript 2.8. Previously in this chapter, we learned that we could use the extends keyword to declare generic constraints. When we declare a generic constraint, we are using the extends keyword as a kind of operator that allows us to check if a generic type (T) is a subtype of a given type. For example, the following code snippet declares two interfaces named Animal and Dog:
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
We then use the extends keyword as a conditional operator to generate a new type:
type Foo1 = Dog extends Animal ? number : string; // number
type Bar1 = RegExp extends Dog ? number : string; // string
Conditional types can be used to declare some complex types. For example, the Flatten function is a function that transforms a multi-dimensional array ([][]) into an array with only one dimension ([]). The type of the return of Flatten function is a conditional type, because it returns an array when a multidimensional array is provided and a number when an array with only one dimension is provided:
type Flatten<T> = T extends any[] ? T[number] : T;
type arr1 = number[];
type flattenArr1 = Flatten<arr1>; // number
type arr2 = number[][];
type flattenArr2 = Flatten<arr2>; // number[]