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

Parameters does not factor in generics or overloads #43731

Closed
didii opened this issue Apr 19, 2021 · 5 comments
Closed

Parameters does not factor in generics or overloads #43731

didii opened this issue Apr 19, 2021 · 5 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@didii
Copy link

didii commented Apr 19, 2021

Bug Report

🔎 Search Terms

  • "parameters with generic function"
  • "generic function wrapping"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Type System Behavior, Generics,

⏯ Playground Link

Playground link with relevant code

💻 Code

declare function foo<TState, T>(
  s1: TState,
  project: (s1: TState) => T): T;
declare function foo<TState1, TState2, T>(
  s1: TState1,
  s2: TState2,
  project: (s1: TState1, s2: TState2) => T): T;

// This is not what I would expect
type Args = Parameters<typeof foo>; // = [s1: unknown, s2: unknown, project: (s1: unknown, s2: unknown) => unknown]

// Something I would have expected
type Expected<TState, T, TState1, TState2> =
  [s1: TState, project: (s1: TState) => T]
  | [s1: TState1, s2: TState2, project: (s1: TState1, s2: TState2) => T];


// Even if it were to return the expected type, it still would not work
function wrapper<TState, T, TState1, TState2>(...args: Expected<TState, T, TState1, TState2>) {
  return foo(...args);
  //         ^^^^^^^ Expected 2-3 arguments, but got 0 or more.(2556)
}

🙁 Actual behavior

The Parameters type seems to choose either the last or a random overload of the given method instead of all of them. Also doesn't factor in generics and converts them to unknown instead.
Even if it would return what I would have expected (see Expected type in example), it still isn't usable in practice.

🙂 Expected behavior

That Args would result in something similar to Expected. All of the overloads should be factored in and also generics.
The Expected args should be usable on foo.

Real-world usages

Any wrapper function where the original function is complex, has overloads or is generic. In our case, it's everything :)

More specifically I want to reduce boilerplating with @ngrx so I wanted to wrap the function createSelector which is declared here, which is similar to the foo of my example, but with 31 overloads instead of only 2 and where the return type is dependent on the parameters (the project argument).

Wrapping this method is possible, but requires just an insane amount of copy-pasting with some little changes which isn't feasible and does not exactly help in reducing the amount of code.

@didii didii changed the title Parameters does not factor in generics Parameters does not factor in generics or overloads Apr 19, 2021
@MartinJohns
Copy link
Contributor

Parameters<T> is based on type inferrence in conditional types, and type inferrence in conditional types does not support overloading: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types

This is a known design limitation.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Apr 19, 2021
@didii
Copy link
Author

didii commented Apr 21, 2021

Thanks for clarifying. Bummer that it isn't supported yet. Are there any plans to support this? I can't see anything about it in the roadmap at the moment.

@MartinJohns
Copy link
Contributor

I haven't seen any mention regarding this by the TypeScript team, so I wouldn't get my hopes up.

@didii
Copy link
Author

didii commented Apr 21, 2021

I'd actually still want to add to this that generics are also not supported since they all get converted to unknown. And this is something the documentation that was linked does not mention at all.

Here is the same playground, but without the overloads: Playground

@MartinJohns
Copy link
Contributor

Because WrapperType is not generic. You can't pass along generic types like this. I think this would require #1213.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

3 participants