- Abstract class
- Annotations
- Array
- Asserts
- Class
- Const
- Decorators
- Default parameter
- Dictionary
- Enum
- For loop
- forEach()
- Function
- Generics
- Index signature
- Infer
- Inheritance
- Interface
- Let
- Map type
- Mixin
- Module
- Namespace
- Never
- Object type
- Operator
- Optional parameter
- Promise
- Property
- Tuples
- Type alias
- Type guard
- Type narrowing
- Union
- Utility types
- Var
- Void
TYPESCRIPT
TypeScript Infer: Syntax, Usage, and Examples
The TypeScript infer
keyword lets you extract and reuse types during conditional type evaluation. You can think of it as TypeScript's way of saying, “Figure out what this type is and give it a name I can use later.” The infer TypeScript
feature shines when you’re building utility types, writing generic functions, or customizing type transformations.
How to Use Infer in TypeScript
You use the infer
keyword inside a conditional type. It allows you to pull out part of a type and name it temporarily. Here's the basic syntax:
type InferSomething<T> = T extends SomeType<infer U> ? U : never;
In this example, if T
matches SomeType<X>
, then U
becomes that X
. If not, the result is never
.
Let’s look at a simple real-world example using arrays:
type ElementType<T> = T extends (infer U)[] ? U : T;
type A = ElementType<string[]>; // string
type B = ElementType<number>; // number
If T
is an array, the infer
keyword pulls out its item type. If it’s not, it just returns the type as is. That’s the core magic of infer in TypeScript_—it gives you dynamic type extraction while keeping everything safe and explicit.
When to Use Infer in TypeScript
You reach for TypeScript infer
when:
- You want to pull out a part of a more complex type (like an item from an array or a return type from a function).
- You’re writing generic utility types.
- You need to transform one type into another while preserving relationships.
- You want your types to behave differently depending on the input shape.
- You’re working with third-party types and need more flexibility.
You won’t use infer
every day, but when you do, it can simplify even the most twisted type logic.
Examples of Infer TypeScript in Action
Infer a Function's Return Type
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
type MyFunction = () => string;
type Result = ReturnTypeOf<MyFunction>; // string
In this example, infer R
pulls out the return type of a function. If T
is a function, the conditional type returns its output type.
Infer from an Array
type FirstElement<T> = T extends [infer First, ...any[]] ? First : never;
type A = FirstElement<[number, string, boolean]>; // number
type B = FirstElement<[]>; // never
Here, infer
pulls out the first element of a tuple. It's useful when analyzing structured data or form responses.
Infer a Promise's Resolved Type
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type A = UnwrapPromise<Promise<number>>; // number
type B = UnwrapPromise<string>; // string
You can build powerful async-aware utilities this way. Whether you're handling API responses or chaining promises, infer simplifies the underlying types.
Infer Arguments from a Function
type Params<T> = T extends (...args: infer P) => any ? P : never;
type MyFunc = (a: string, b: number) => void;
type ArgTypes = Params<MyFunc>; // [string, number]
If you're building wrappers or decorators, this trick helps you extract argument types directly from the function signature.
Infer in Recursive Utility Types
type Flatten<T> = T extends Array<infer U> ? Flatten<U> : T;
type A = Flatten<number[][][]>; // number
This recursively pulls out the deepest type in a nested array. It’s great for working with JSON-like structures.
Learn More About Infer in TypeScript
How Infer Works Under the Hood
When TypeScript evaluates a conditional type with infer
, it tries to match the left side to a pattern. If the match is successful, it binds the inferred type to the name you provide (U
, T
, etc.). If the match fails, the type falls back to whatever comes after the :
in the conditional.
This makes infer in TypeScript behave a little like destructuring—but for types.
Combining Infer with Generics
Infer really shines inside generic utility types:
type Callback<T> = T extends (value: infer R) => void ? R : never;
type A = Callback<(x: boolean) => void>; // boolean
You’re not just inferring blindly—you’re tying inference to specific input types so your logic stays strong and reusable.
Narrowing Inferred Types
Once you infer a type, you can use it in additional conditional logic:
type DeepType<T> =
T extends { nested: infer U }
? U extends { inner: infer V }
? V
: never
: never;
type A = DeepType<{ nested: { inner: string } }>; // string
This works like a step-by-step unpacking of nested structures.
Infer with Tuples and Rest Parameters
Tuples offer rich structures to explore with infer
:
type Last<T extends any[]> = T extends [...any[], infer L] ? L : never;
type A = Last<[1, 2, 3]>; // 3
This infer
example grabs the last element in a tuple.
You can also split and manipulate parameter lists:
type RemoveFirst<T extends any[]> = T extends [any, ...infer Rest] ? Rest : never;
type A = RemoveFirst<[string, number, boolean]>; // [number, boolean]
You’re not limited to objects or functions—infer
works with arrays too.
Infer with Conditional Mapping
type ToString<T> = T extends number ? `${T}` : never;
type ID = ToString<123>; // "123"
This is technically not using infer
, but often paired with it in type transformations where you create new string literal types based on inferred values.
Best Practices for Using Infer in TypeScript
- Only use
infer
inside conditional types. - Name your inferred types clearly—avoid using single letters if they don’t convey intent.
- Combine with generic constraints to keep your types readable and maintainable.
- Use
infer
when existing utility types don't cover your case. - Don’t overuse infer. If a simpler approach works, go with that.
- Always test inferred types using
type
aliases or utility checks in your IDE.
Common Patterns with TypeScript Infer
Building Your Own ReturnType
You don’t always need the built-in utility types. Here’s how you’d write your own:
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
This is exactly what TypeScript’s native ReturnType<T>
does.
Conditional Behavior Based on Inferred Value
You can use infer
to check how deep a type goes and respond accordingly:
type HasPromise<T> = T extends Promise<infer _> ? true : false;
type A = HasPromise<Promise<number>>; // true
type B = HasPromise<string>; // false
This makes it easy to write responsive utility types that adapt based on shape.
The TypeScript infer keyword gives you a tool for smart, reactive type transformations. Whether you're working with deeply nested arrays, composing generic utilities, or building libraries with flexible APIs, infer TypeScript
capabilities help you write code that’s both safe and powerful. It may not be the first tool you reach for, but once you understand it, it becomes an essential part of your TypeScript toolkit.
Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.