Understanding the infer Keyword in TypeScript
Daniel Hayes
Full-Stack Engineer · 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:
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:
type Moment<T> = T extends infer U ? U : never; type StringType = Moment<string>; // string type NumberType = Moment<number>; // number type UnionType = Moment<string | number>; // string | number interface User { name: string; age: number; } type UserType = Moment<User>; // User
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:
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never; type ExampleFunction = (x: number, y: string) => boolean; type ReturnTypeOfExampleFunction = GetReturnType<ExampleFunction>; // boolean
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:
type GetArrayElementType<T> = T extends (infer U)[] ? U : never; type Moment = string[]; type Example1Array = Array<string>; type ElementTypeOfExampleArray = GetArrayElementType<Moment>; // string type ElementTypeOfExample1Array = GetArrayElementType<Example1Array>; // string
Here, we use T extends (infer U)[] to infer the element type U of the array. Since T is string[], U becomes string.
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:
type GetPromiseValueType<T> = T extends Promise<infer U> ? U : never; // Example type ExamplePromise = Promise<number>; type ValueTypeOfExamplePromise = GetPromiseValueType<ExamplePromise>; // number
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:
type GetParameters<T> = T extends (...args: infer P) => any ? P : never; type ExampleFunction = (a: number, b: string) => void; type Params = GetParameters<ExampleFunction>; // [number, string]
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:
type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never; class ExampleClass { constructor(public a: number, public b: string) {} } type Params = ConstructorParameters<typeof ExampleClass>; // [number, string]
Complex Inference in Conditional Types
Suppose we need to use complex inference logic within a conditional type:
type IsArray<T> = T extends (infer U)[] ? U : never; type IsFunction<T> = T extends (...args: any[]) => infer R ? R : never; type ExtractType<T> = T extends any[] ? IsArray<T> : T extends (...args: any[]) => any ? IsFunction<T> : T; // Example type ArrayType = ExtractType<string[]>; // string type FunctionReturnType = ExtractType<() => number>; // number type DefaultType = ExtractType<boolean>; // boolean
In this code:
type ExtractType<T> = T extends any[] ? IsArray<T> : T extends (...args: any[]) => any ? IsFunction<T> : T;
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.
We are Leapcell, your top choice for hosting Node.js projects.
Leapcell is the Next-Gen Serverless Platform for Web Hosting, Async Tasks, and Redis:
Multi-Language Support
- Develop with Node.js, Python, Go, or Rust.
Deploy unlimited projects for free
- pay only for usage — no requests, no charges.
Unbeatable Cost Efficiency
- Pay-as-you-go with no idle charges.
- Example: $25 supports 6.94M requests at a 60ms average response time.
Streamlined Developer Experience
- Intuitive UI for effortless setup.
- Fully automated CI/CD pipelines and GitOps integration.
- Real-time metrics and logging for actionable insights.
Effortless Scalability and High Performance
- Auto-scaling to handle high concurrency with ease.
- Zero operational overhead — just focus on building.
Explore more in the Documentation!
Follow us on X: @LeapcellHQ



