Question
Get Function Argument Types with Parameters in TypeScript
Question
Given this TypeScript function:
function test(a: string, b: number) {
console.log(a);
console.log(b);
}
How can I obtain the parameter types, string and number, as a tuple type? For example, I can use typeof test to get the function type and ReturnType<typeof test> to get its return type. Is there an equivalent utility type for a function's arguments?
Also, why does keyof typeof test evaluate to never, and how does the extends syntax used in conditional-type solutions work?
Short Answer
TypeScript represents a function's parameter list as a tuple type. Use the built-in Parameters<T> utility to extract that tuple from a function type. You will also learn why typeof is needed for function declarations, why keyof is not used for parameters, and how conditional types can implement the same idea.
Concept
A function has a function type describing its inputs and output. For example, this function:
function test(a: string, b: number): void {
console.log(a, b);
}
has a type similar to:
(a: string, b: number) => void
Its input types can be represented as the tuple:
type TestArguments = [a: string, b: number];
TypeScript provides the built-in Parameters<T> utility type to extract this tuple:
type TestArguments = Parameters<typeof test>;
// [a: string, b: number]
This matters when you want one type definition to stay synchronized with a function. If the function's parameters change later, every place that uses receives the updated tuple automatically.
Mental Model
Think of a function as a machine with an input tray and an output slot.
typeof testis the machine's instruction sheet: it says the machine accepts astringand anumber.Parameters<typeof test>reads the input tray requirements and returns[string, number].ReturnType<typeof test>reads the output slot requirement and returns the output type.keyof typeof testasks for named properties on the machine object, such as.nameor custom attached properties. It does not ask what belongs in the input tray.
Syntax and Examples
Use Parameters<T> with a function type.
function test(a: string, b: number): void {
console.log(a, b);
}
type TestParameters = Parameters<typeof test>;
// type TestParameters = [a: string, b: number]
const validArguments: TestParameters = ["Ada", 42];
test(...validArguments);
TestParameters is a tuple, not merely (string | number)[]. Tuple positions are preserved:
- the first item must be a
string - the second item must be a
number
const invalidArguments: TestParameters = [42, "Ada"];
// Error: number is not assignable to string
Step by Step Execution
Consider a reusable logging wrapper:
function formatPrice(amount: number, currency: string): string {
return `${currency} ${amount.toFixed(2)}`;
}
type PriceArguments = Parameters<typeof formatPrice>;
const args: PriceArguments = [19.5, "USD"];
const result = formatPrice(...args);
Step by step:
-
typeof formatPriceproduces the function type:(amount: number, currency: string) => string -
Parameters<typeof formatPrice>inspects the function's parameter list. -
It creates this tuple type:
Real World Use Cases
Parameters<T> is useful whenever another API should accept exactly the same arguments as an existing function.
- Logging or timing wrappers: Forward a function's arguments without manually repeating their types.
- Event handlers: Reuse the argument list of a callback or listener.
- Test helpers: Create typed helpers that invoke production functions with valid inputs.
- Dependency injection: Store constructor or factory arguments in a correctly typed tuple.
- API clients: Reuse argument types for retry, caching, or telemetry layers.
Example: a generic function caller:
function callLater<F extends (...args: any[]) => any>(
fn: F,
args: Parameters<F>
): void {
setTimeout(() => fn(...args), 1000);
}
function greet(name: string, excited: boolean): void {
console.log(excited ? `Hello, ${name}!` : `Hello, ${name}.`);
}
callLater(greet, [, ]);
Real Codebase Usage
In real projects, Parameters<T> is commonly paired with generics and argument forwarding.
Typed wrapper functions
A wrapper can preserve the argument list and return type of any callback:
function withLogging<F extends (...args: any[]) => any>(fn: F) {
return (...args: Parameters<F>): ReturnType<F> => {
console.log("Calling with:", args);
return fn(...args);
};
}
function add(left: number, right: number): number {
return left + right;
}
const loggedAdd = withLogging(add);
const total = loggedAdd(2, 3);
loggedAdd is inferred as (left: number, right: number) => number.
Typed constructor arguments
Common Mistakes
Forgetting typeof for a function declaration
test is a value name, not a type name.
function test(a: string, b: number): void {}
type Args = Parameters<test>;
// Error: 'test' refers to a value, but is being used as a type here.
Use:
type Args = Parameters<typeof test>;
Using ReturnType<test> instead of ReturnType<typeof test>
The same value-versus-type rule applies:
type Result = ReturnType<typeof test>;
Using keyof to get arguments
keyof gets property names from object types. Function parameters are not object properties.
Comparisons
| Tool or technique | What it extracts or does | Example result |
|---|---|---|
Parameters<F> | Parameter tuple from a function type | [string, number] |
ReturnType<F> | Return type from a function type | string |
ConstructorParameters<C> | Constructor parameter tuple | [name: string] |
typeof value | Type of a runtime value | (a: string) => void |
keyof T | Property names of an object type |
Cheat Sheet
// Function declaration: use typeof
type Args = Parameters<typeof myFunction>;
type Result = ReturnType<typeof myFunction>;
// Function type alias: no typeof needed
type Handler = (id: string, retry?: boolean) => Promise<void>;
type HandlerArgs = Parameters<Handler>;
// [id: string, retry?: boolean | undefined]
// Individual tuple elements
type First = Parameters<typeof myFunction>[0];
// Forward arguments in a generic wrapper
function wrap<F extends (...args: any[]) => any>(fn: F) {
return (...args: Parameters<F>): ReturnType<F> => fn(...args);
}
Rules:
FAQ
How do I get argument types from a function in TypeScript?
Use Parameters<typeof functionName>. For example, Parameters<typeof test> produces [a: string, b: number].
Why do I need typeof in Parameters<typeof test>?
test is a JavaScript value. typeof test converts that value reference into its TypeScript type so a type utility can use it.
Does Parameters<T> include optional parameters?
Yes. For (id: string, verbose?: boolean) => void, it produces [id: string, verbose?: boolean | undefined].
Does Parameters<T> work with rest parameters?
Yes. For (...values: number[]) => number, it produces number[] as the parameter tuple/rest representation.
Why does keyof typeof test return never?
keyof asks for named properties, not function inputs. A normal function declaration has no declared custom properties, so there are no keys to produce.
Mini Project
Description
Build a typed once wrapper. It wraps a function so it can run only once, while retaining the exact parameter and return types of the original function. This pattern is useful for one-time initialization, lazy setup, and preventing duplicate actions.
Goal
Create a reusable wrapper that accepts only valid arguments for the wrapped function and returns its original result.
Requirements
Define a generic once function that accepts a function.
Use Parameters<F> to preserve the wrapped function's arguments.
Use ReturnType<F> to preserve the wrapped function's result type.
Ensure the wrapped function runs only on its first call.
Demonstrate the wrapper with a function that accepts a string and a number.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.