Skip to content

"...args: infer" on an overloaded function chooses only one function head #26136

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

Closed
mike-north opened this issue Aug 1, 2018 · 5 comments
Closed
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds

Comments

@mike-north
Copy link

TypeScript Version: 3.1.0-dev.20180801

Search Terms: overload, infer, function heads, tuple, rest parameter

Code

interface Foo {
  (a: string, b: number, c: boolean): void;
  (a: number, b: string, c: boolean): void;
}

type Args<F> = F extends (...args: infer T) => any ? T : never;

let x: Args<Foo> = [42, 'hello world', true]; // ✅
x = ['hello world', 42, true]; // 💥

Expected behavior:
Ideally, I would hope for the typeof x to be

let x: [string, number, boolean] | [number, string, boolean]

although not entirely correct, I would even take a type wide enough to accomodate both function heads.

let x: [string|number, number|string, boolean]

Actual behavior:
The type of x ends up being

let x: [number, string, boolean]

Playground Link: https://www.typescriptlang.org/play/#src=interface%20Foo%20%7B%0D%0A%20%20(a%3A%20string%2C%20b%3A%20number%2C%20c%3A%20boolean)%3A%20void%3B%0D%0A%20%20(a%3A%20number%2C%20b%3A%20string%2C%20c%3A%20boolean)%3A%20void%3B%0D%0A%7D%0D%0A%0D%0Atype%20Args%3CF%3E%20%3D%20F%20extends%20(...args%3A%20infer%20T)%20%3D%3E%20any%20%3F%20T%20%3A%20never%3B%0D%0A%0D%0Alet%20x%3A%20Args%3CFoo%3E%20%3D%20%5B42%2C%20'hello%20world'%2C%20true%5D%3B%20%2F%2F%20%E2%9C%85%0D%0Ax%20%3D%20%5B'hello%20world'%2C%2042%2C%20true%5D%3B%20%2F%2F%20%F0%9F%92%A5

Related Issues: #24897, #5453 (maybe)

@mike-north
Copy link
Author

Closing as duplicate of @bterlson's #26132

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Aug 2, 2018
@bterlson
Copy link
Member

bterlson commented Aug 2, 2018

@mike-north is this a duplicate, though? #26132 doesn't have overloads, and arguments list inference of fn gives something similar to what you request here:

// sample from #26132

type Rec = {
  foo: (a: string, b: number) => void,
  bar: (b: boolean, c: RegExp) => void,
}

type Parameters<T> = T extends (...args: infer U) => any ? U : never;

declare var fn: <K extends keyof Rec>(e: K, ...args: Parameters<Rec[K]>) => void;

// test parameter extraction
type test = Parameters<typeof fn>;
// type test = ["foo" | "bar", ...(string | number | boolean | RegExp)[]]

@mike-north
Copy link
Author

Good catch, I must have read your issue too quickly. Maybe this should be un-tagged as duplicate

@mike-north mike-north reopened this Aug 2, 2018
@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript In Discussion Not yet reached consensus and removed Duplicate An existing issue was already created labels Aug 2, 2018
@RyanCavanaugh RyanCavanaugh added Too Complex An issue which adding support for may be too complex for the value it adds and removed In Discussion Not yet reached consensus labels Aug 7, 2018
@RyanCavanaugh
Copy link
Member

Discussed for a while yesterday. This looks reasonably straightforward if you're just capturing the entire parameter list into a single spread, but quickly turns into a bunch of really complicated questions once you do anything else

  • What would the behavior of type Args<F> = F extends (n: number, ...args: infer T) => any ? T : never; be? Would it be sound to just capture the matching overloads, or not?
  • What happens when you put T into a different argument list? Potentially a combinatorially explosive expansion in to overloads?
  • More problems I can't recall at the moment

Overall too complex unless there are some important use cases that appear.

@spiritwindy
Copy link

@RyanCavanaugh
some example like
Function.prototype.call
Function.prototype.apply
Function.prototype.bind

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds
Projects
None yet
Development

No branches or pull requests

4 participants