Skip to main content

How do you extract a function's argument types with infer?

TypeScript lets you extract a function's argument types using the infer keyword inside conditional types. This is one of the most common and useful use cases for infer.


The general idea

We check that some type T is a function, and we tell TypeScript:

"If T is a function whose arguments have type A, infer that A."


Example 1: Extract the type of one argument

javascript
type FirstArg<T> = T extends (arg: infer A) => any ? A : never; type Example = (x: number) => void; type Result = FirstArg<Example>; // number

Here:

  • T extends (arg: infer A) => any checks whether T is a function.
  • infer A is how TypeScript "pulls out" the type of the first argument.
  • If T is not a function, the result is never.

Example 2: Extract all of a function's arguments as a tuple

javascript
type Args<T> = T extends (...args: infer A) => any ? A : never; type Fn = (x: number, y: string) => boolean; type Params = Args<Fn>; // [number, string]

In this case infer A becomes a tuple of argument types.


Example 3: Extract the return type

javascript
type Return<T> = T extends (...args: any[]) => infer R ? R : never; type Fn = (x: number, y: string) => boolean; type R = Return<Fn>; // boolean

This is the implementation behind the built-in ReturnType<T>.


Example 4: Get both the arguments and the result

javascript
type FunctionParts<T> = T extends (...args: infer A) => infer R ? { args: A; return: R } : never; type Fn = (id: string, active: boolean) => number; type Parts = FunctionParts<Fn>; /* { args: [string, boolean]; return: number; } */

Example 5: The first argument

javascript
type FirstArg<T> = T extends (...args: [infer First, ...any[]]) => any ? First : never; type Fn = (name: string, age: number) => void; type A = FirstArg<Fn>; // string

This uses tuple destructuring: [infer First, ...any[]].


Example 6: The last argument

javascript
type LastArg<T> = T extends (...args: [...any[], infer Last]) => any ? Last : never; type Fn = (a: number, b: string, c: boolean) => void; type L = LastArg<Fn>; // boolean

Example 7: The argument types of a class method

javascript
class User { save(id: number, active: boolean) {} } type MethodArgs = Args<User["save"]>; // [number, boolean]

Works for any method - just take the type by key ["methodName"] and apply the utility.


Example 8: Implementing an analog of the built-in Parameters<T>

TypeScript already has a ready-made utility type:

javascript
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer A) => any ? A : never; type Fn = (x: number, y: string) => boolean; type Params = MyParameters<Fn>; // [number, string]

This is the equivalent of the standard Parameters<Fn>.


Example 9: Getting the argument type of a callback function

javascript
type Callback = (err: Error | null, data: string) => void; type CallbackArgs = Args<Callback>; // [Error | null, string]

Often used when typing APIs, Node.js callbacks, React hooks, and so on.


Example 10: Applying the arguments to another function

javascript
type Args<T> = T extends (...args: infer A) => any ? A : never; function call<T extends (...args: any[]) => any>(fn: T, ...args: Args<T>) { return fn(...args); } function greet(name: string, age: number) { return `${name}, ${age}`; } call(greet, "Tim", 25); // ok call(greet, 25, "Tim"); // type error

Here Args<T> guarantees the correct order and types of the arguments.


Summary

What we extractExampleResult
One argumentT extends (a: infer A) => anythe type of the first argument
All argumentsT extends (...args: infer A) => anya tuple of arguments
Return valueT extends (...args: any[]) => infer Rthe result type
First argumentT extends (...args: [infer F, ...any[]]) => anythe first argument
Last argumentT extends (...args: [...any[], infer L]) => anythe last argument

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.