10

Given an overloaded function example.

function example(a: string): number
function example(a: string, b?: string): number { 
  return 1
}

type Result = Parameters<typeof example>

I'd expect Result to contain ALL options for arguments of example, not just the first / top-most argument set. How can I get the parameters?

2

1 Answer 1

12

In the answers to the question this duplicates the limitation mentioned in @ford04's answer here, that infer only looks at the last overloaded signature, is acknowledged. This is a missing feature or design limitation of TypeScript; see microsoft/TypeScript#29732 for a relevant feature request.

But this answer shows it's not completely impossible; you can tease out some information about overloads, at least for functions with up to some arbitrary fixed number of them (this is still true as of TypeScript 4.8; recursive conditional types don't help). But it's hairy and ugly and there might be bugs in it, see microsoft/TypeScript#28867. Here's one way of doing it:

type Overloads<T> =
  T extends {
    (...args: infer A1): infer R1;
    (...args: infer A2): infer R2;
    (...args: infer A3): infer R3;
    (...args: infer A4): infer R4
  } ? [
    (...args: A1) => R1,
    (...args: A2) => R2,
    (...args: A3) => R3,
    (...args: A4) => R4
  ] : T extends {
    (...args: infer A1): infer R1;
    (...args: infer A2): infer R2;
    (...args: infer A3): infer R3
  } ? [
    (...args: A1) => R1,
    (...args: A2) => R2,
    (...args: A3) => R3
  ] : T extends {
    (...args: infer A1): infer R1;
    (...args: infer A2): infer R2
  } ? [
    (...args: A1) => R1,
    (...args: A2) => R2
  ] : T extends {
    (...args: infer A1): infer R1
  } ? [
    (...args: A1) => R1
  ] : any

type OverloadedParameters<T> =
  Overloads<T> extends infer O ?
  { [K in keyof O]: Parameters<Extract<O[K], (...args: any) => any>> } : never

type OverloadedReturnType<T> =
  Overloads<T> extends infer O ?
  { [K in keyof O]: ReturnType<Extract<O[K], (...args: any) => any>> } : never

The Overloads<T> type alias takes a function type T and returns a tuple of its call signatures (for up to four overloads). And OverloadedParameters<T> and OverloadedReturnType<T> map Parameters<T> and ReturnType<T> over that tuple, respectively.

Let's see it in action (after correcting your example so that it actually has multiple overloads, as done in the other answer):

function example(a: string): number
function example(a: string, b: string): number
function example(a: string, b?: string): number {
  return 1
}

type ExampleOverloads = Overloads<typeof example>
// type ExampleOverloads = [(a: string) => number, (a: string, b: string) => number]

type ExampleParameters = OverloadedParameters<typeof example>
// type ExampleParameters = [[string], [string, string]]

Looks reasonable to me. Okay, hope that helps; good luck!

Link to code

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the info and the issue hint (+1). While I probably would not use this in production, this is interesting inference behavior.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.