Conditional types are a powerful feature in TypeScript that allows you to express complex type relationships and transformations based on conditions. They can be thought of as a form of type-level logic that makes your type definitions more expressive and flexible.
A conditional type has the following form:
T extends U ? X : Y
Here, ‘T‘ and ‘U‘ are types, and ‘X‘ and ‘Y‘ are the resulting types. The basic idea is the following:
- If ‘T‘ is assignable to ‘U‘ (i.e., ‘T extends U‘), then the resulting type is ‘X‘.
- Otherwise, the resulting type is ‘Y‘.
Let’s take a look at a simple example to illustrate this concept:
type IsString<T> = T extends string ? true : false;
In this case, we define a conditional type called ‘IsString‘, which checks whether the type ‘T‘ is a ‘string‘. If it is, the type evaluates to ‘true‘. Otherwise, it evaluates to ‘false‘.
Here’s how ‘IsString‘ can be used with different types:
type A = IsString<string>; // true
type B = IsString<number>; // false
Now let’s consider a more complex example using conditional types to define a utility type for extracting the return type of a function:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
Here’s a step-by-step explanation of this conditional type:
1. Check if ‘T‘ extends a function type with the form ‘(...args: any[]) => any‘. If it doesn’t, the type evaluates to ‘never‘.
2. If ‘T‘ does extend the function type, use the ‘infer‘ keyword to infer the return type ‘R‘ of the function.
3. If the inference is successful, the type evaluates to ‘R‘. Otherwise, it evaluates to ‘never‘.
Let’s see how the ‘ReturnType‘ utility type works in practice:
type C = ReturnType<() => string>; // string
type D = ReturnType<(x: number, y: number) => boolean>; // boolean
The conditional type can be represented as:
T ⊆ U ⇒ X | X̄ ⇒ Y
In this formula, T is the tested type, U is the constraint type. If T is assignable to U (T ⊆ U), the resulting type is X. Otherwise, the resulting type is Y.
I hope this explanation helps you understand the concept of conditional types in TypeScript!