typescriptmethodsparametersoverloadingutility

Typescript pick only specific method from overload (to be passed to Parameters<T>)


Background

So I have a problem getting specific Parameters from a function which is overloaded. For example:

// someLib.d.ts
type Component<T> = {};
type A = {};
type B = {};
type C = {};
type Opts = {};
type ModernOpts = {};

export declare function mount(component: A, options: Opts): Component<A>;
export declare function mount(component: B, options: Opts): Component<B>;
export declare function mount(component: C, options: ModernOpts): Component<C>;

The problem is, somehow if I do this on another file:

import { mount } from 'someLib';

type specificMountParams = Parameters<typeof mount>;

The param I get is [C, ModernOpts], and it seems like there's no way to get the parameter of [A, Opts], or [B, Opts].

Question

Is there any way to retrieve specific parameter from overloaded functions? (So I can get [A, Opts] parameter)

Limitation and Info

Those types (A, B, Opts) are not exported by the library, and I need to create a function that needs such type to do something similar.


Solution

  • From the docs:

    When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types.

    COnsider this example:

    function foo(a: number): number
    function foo(a: string): string // last signature
    function foo(a: number | string): number | string {
      return null as any
    }
    
    type Fn = typeof foo
    
    // returns last overloaded signature
    type Arguments = Parameters<Fn> // [a: string]
    

    Parameters always returns last overdloaded signature of function.

    Try to change the order:

    function foo(a: string): string 
    function foo(a: number): number// last signature
    function foo(a: number | string): number | string {
      return null as any
    }
    
    type Fn = typeof foo
    
    // returns last overloaded signature
    type Arguments = Parameters<Fn> // [a: number]
    

    There is no way to return a union of all parameters because it is unsound. See official explanation here

    It's not really possible to make this in a way that's both useful and sound. Consider a function like

    declare function fn(n1: number, n2: number): void;
    
    declare function doCall<T extends (a1: any, a2: any) => void>(func: T,
    a0: Parameters<T>[0], a1: Parameters<T>[1]): void; ```
    
    

    If Parameters<T>[0] returns string | number, then doCall(fn, 0, "") would incorrectly succeed. If Parameters<T>[0]> returns string & number, then doCall(fn, 0, 0) would incorrectly fail (and be a big breaking change). Notably, with conditional types and unions, really the only kind of functions that can't be typed with a single overload are exactly the ones that have this failure mode.

    The current behavior at least makes it so that some calls are correctly accepted.

    You can find some workarounds in above github thread