repost: A Deep Dive into TypeScript’s infer Keyword - Leapcell
The infer keyword in TypeScript is used in conditional types to infer a type. This is particularly useful when dealing with complex types, allowing us to extract or transform types.
# Basic Usage
The infer keyword can only be used within conditional types, typically in conjunction with generics and the extends keyword. The syntax is as follows:
1 | type Moment<T> = T extends infer U ? U : never; |
Here, T extends infer U means that we attempt to infer the type T and assign it to U . If type inference succeeds, then U becomes the inferred type.
We can use it to infer different types. Here are a few examples:
1 | type Moment<T> = T extends infer U ? U : never; |
In these examples, Moment<T> essentially just returns the type T without any conversion or processing. This primarily serves to demonstrate the basic usage of conditional types and type inference.
# Common Examples
# Extracting a Function’s Return Type
Suppose we have a function type and we want to extract its return type. We can do this:
1 | type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never; |
In the code above:
T extends (...args: any[]) => infer R: This checks whetherTis a function type.(...args: any[])means the function can accept any number of arguments.infer R: IfTis a function type, theninfer Rinfers the function’s return type and assigns it to type variableR.? R : never: IfTis a function type, the inferred return typeRis returned; otherwise,neveris returned.
# Extracting an Array’s Element Type
We can also use infer to extract the element type of an array:
1 | type GetArrayElementType<T> = T extends (infer U)[] ? U : never; |
Here, we use T extends (infer U)[] to infer the element type U of the array. Since T is string[] , U becomes string .
1 | string[] extends (infer U)[ ] |
It is important to note that infer declarations are only allowed within the extends clause of conditional types, and the type variable declared with infer is only available within the true branch.
# Advanced Examples
# Extracting the Value Type of a Promise
If we have a Promise type, we can extract its resolved value type:
1 | type GetPromiseValueType<T> = T extends Promise<infer U> ? U : never; |
In the code above:
T extends Promise<infer U>: This checks whetherTis aPromisetype.infer U: IfTis aPromisetype,infer Uinfers the resolved value type of thePromiseand assigns it toU.? U : never: IfTis aPromisetype, the inferred value typeUis returned; otherwise,neveris returned.
# Extracting a Function’s Parameter Types
Sometimes, we need to obtain the parameter types of a function. We can use infer to achieve this:
1 | type GetParameters<T> = T extends (...args: infer P) => any ? P : never; |
In the code above:
T extends (...args: infer P) => any: This checks whetherTis a function type.infer P: IfTis a function type,infer Pinfers the function’s parameter types and assigns them toP.? P : never: IfTis a function type, the inferred parameter typesPare returned; otherwise,neveris returned.
# Extracting Constructor Parameter Types
We can also use infer to extract the parameter types of a class constructor:
1 | type ConstructorParameters<T> = T extends new (...args: infer P) => any |
# Complex Inference in Conditional Types
Suppose we need to use complex inference logic within a conditional type:
1 | type IsArray<T> = T extends (infer U)[] ? U : never; |
In this code:
1 | type ExtractType<T> = T extends any[] |
T extends any[] ? IsArray<T>: IfTis an array type, returnIsArray, which extracts the element type of the array.T extends (...args: any[]) => any ? IsFunction<T>: IfTis a function type, returnIsFunction, which extracts the function’s return type.T: IfTis neither an array type nor a function type, returnTitself.
# Summary
The infer keyword is used in conditional types to infer a new type variable from another type. It allows extracting and utilizing specific subtypes or properties during type checking, enhancing the expressiveness and flexibility of TypeScript’s type system. In simple terms, infer helps automatically extract the desired parts from complex types.