Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A type util to produce an alternation of function overloads. #868

Open
unphased opened this issue Apr 23, 2024 · 1 comment
Open

A type util to produce an alternation of function overloads. #868

unphased opened this issue Apr 23, 2024 · 1 comment

Comments

@unphased
Copy link

unphased commented Apr 23, 2024

Example situation:

type F = {
    (thing: string): void;
    (things: string[]): void;
}

type Z = Parameters<F>[0]

Type Z here resolves to string[], not string | string[], because overloads just get the last declared one matched.

I am curious to know if this is possible to implement. As far as I can tell this also affects the standard function overload approach, e.g.:

function fun(thing: string): void; 
function fun(stuff: string[]): void;
// function fun(thing: string | string[]); // uncomment me to allow type Y to match `string`.
function fun(thing: string | string[]) { console.log(Array.isArray(thing) ? thing.join('; ') : thing); }

type F = {
    (thing: string): void;
    (things: string[]): void;
}

type Z = Parameters<F>[0]
type Y = Parameters<typeof fun>[0];

let zz:Z = 'abc';
let yy:Y = 'abc';

To be clear, what I'm asking for is a util e.g. OverloadParameters which in this case would produce for type OverloadParameters<F> a value of [string] | [string[]]. I'm actually currently unsure of how to unwrap the parameter-array situation there but I'm sure it's manageable. As expected, the type ([string] | [string[]])[0] is string | string[].

@unphased
Copy link
Author

unphased commented Apr 23, 2024

GPT4 plus testing shows to me that It appears possible to do this via

type OverloadParams<T> = T extends {
  (...args: infer A): any;
  (...args: infer B): any;
} ? A | B : never;

A general solution working for N overloads seems elusive. In practical terms we only ever need this for up to say 5 overloads. So unrolling it seems practical. A recursive implementation would be nice, but may lead to longer compilation time.

This definitely seems to work for me:

type OverloadParams<T> = T extends {
  (...args: infer A);
  (...args: infer B);
  (...args: infer C);
  (...args: infer D);
  (...args: infer E);
} ? A | B | C | D | E : T extends {
  (...args: infer A);
  (...args: infer B);
  (...args: infer C);
  (...args: infer D);
} ? A | B | C | D : T extends {
  (...args: infer A);
  (...args: infer B);
  (...args: infer C);
} ? A | B | C : T extends {
  (...args: infer A);
  (...args: infer B);
} ? A | B : never;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant