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

Leading/Middle Rest Elements in Tuple Types with generic function derive unknown #47487

Closed
ashidaharo opened this issue Jan 18, 2022 · 4 comments
Assignees
Labels
Fixed A PR has been merged for this issue

Comments

@ashidaharo
Copy link

Bug Report

I originally discovered this when I was tinkering with a function that combines the return values of multiple functions into the argument of the last function given, such as reselect. However, as a result of verification, it was found that it can be reproduced just by using Leading/Middle Rest Elements in Tuple Types and generic functions at the same time, which is shown in the simple example below.

🔎 Search Terms

Leading Middle Rest Tuple Arg Argument generic unknown any

🕗 Version & Regression Information

  • This is the behavior in every version from 4.2.3, Leading/Middle Rest Elements in Tuple Types implemented, and I reviewed the FAQ, but couldn't find anything related to this.

⏯ Playground Link

Playground link with relevant code

💻 Code

// Leading
// Set up
type LeadingRestTestType = <Args extends unknown[], Result>(...args:[...Args, (...items: Args) => Result]) => Result;
declare const leadingRestTestFunction: LeadingRestTestType;

// No Error
// const leadingRestTestFunction: <[boolean], boolean>(args_0: boolean, args_1: (items_0: boolean) => boolean) => boolean
const noErrorCase: boolean = leadingRestTestFunction(false, (i) => i);

// Type 'unknown' is not assignable to type 'boolean'.(2322)
// const leadingRestTestFunction: <[boolean], unknown>(args_0: boolean, args_1: (items_0: boolean) => unknown) => unknown
const errorCase: boolean = leadingRestTestFunction(false, <T>(i: T): T => i);


// Middle
// Set up
type MiddleRestTestType = <Args extends unknown[], Result, Foo>(...args:[Foo, ...Args, (...items: Args) => Result]) => Result;
declare const middleRestTestFunction: MiddleRestTestType;

// No Error
// const middleRestTestFunction: <[boolean], boolean, null>(args_0: null, args_1: boolean, args_2: (items_0: boolean) => boolean) => boolean
const sameNoErrorCase: boolean = middleRestTestFunction(null, false, (i) => i);

// Type 'unknown' is not assignable to type 'boolean'.(2322)
// const middleRestTestFunction: <[boolean], unknown, null>(args_0: null, args_1: boolean, args_2: (items_0: boolean) => unknown) => unknown
const theOtherErrorCase: boolean = middleRestTestFunction(null, false, <T>(i: T): T => i);

I also listed other examples in Playground that I suspected would cause the same error because of their similarity, but did not cause the error.

🙁 Actual behavior

When I used Leading/Middle Rest Elements in Tuple Types and generic functions together, the result was inferred to be unknown instead of boolean.
This only happened with Leading/Middle Rest Elements in Tuple Types, unlike Traling, Single Arg, Normal Rest Argument.

🙂 Expected behavior

At the very least, the Result should be correctly inferred into a boolean.
Also, from the point of view of implementing the function, it should be undesirable to have an error in the case of Leading or Middle, even though it does not occur in the case of Trailing.
It seems that there is a more complicated issue between this feature and generic types, because in type inference, when the type <T>(i: T): T => i is instantiated, it is inferred as args_1: (items_0: boolean) => unknown.

@david-shortman
Copy link

Looks related to #47226

@RyanCavanaugh RyanCavanaugh added the Needs More Info The issue still hasn't been fully clarified label Jan 18, 2022
@RyanCavanaugh
Copy link
Member

I can't tell from the report here what you consider expected vs not expected. All of these inferences appear to be sound, and some are underspecific due to limitations in the inference algorithm. If there's a particular case you'd like me to speak to I'm happy to, but I don't have bandwidth to explain what's going on in all 60 lines of code. What's the shortest example you'd consider to be broken?

@ashidaharo
Copy link
Author

ashidaharo commented Jan 18, 2022

I'm sorry that I try to record my trial and error in order to isolate when the problem only occurred. I shouldn't do it.

some are underspecific due to limitations in the inference algorithm.

And maybe this is one of the issues you are referring to in this way. But just in case, let me rewrite a more correct and concise statement.

What's the shortest example you'd consider to be broken?

💻 Code

// Leading
// Set up
type LeadingRestTestType = <Args extends unknown[], Result>(...args:[...Args, (...items: Args) => Result]) => Result;
declare const leadingRestTestFunction: LeadingRestTestType;

// No Error
// const leadingRestTestFunction: <[boolean], boolean>(args_0: boolean, args_1: (items_0: boolean) => boolean) => boolean
const noErrorCase: boolean = leadingRestTestFunction(false, (i) => i);

// Type 'unknown' is not assignable to type 'boolean'.(2322)
// const leadingRestTestFunction: <[boolean], unknown>(args_0: boolean, args_1: (items_0: boolean) => unknown) => unknown
const errorCase: boolean = leadingRestTestFunction(false, <T>(i: T): T => i);

🙁 Actual behavior

In errorCase, Type of return value of leadingRestTestFunction is infered unknown.

🙂 Expected behavior

  • I think this is boolean.
  • and when the type ''(i: T): T => i'' is instantiated, it is inferred as ''args_1: (items_0: boolean) => unknown''. that is a mystery to me This is because the information that the original function had, that the type of the only argument i and the type of the return value are the same, appears to have been lost.

@RyanCavanaugh RyanCavanaugh added Needs Investigation This issue needs a team member to investigate its status. and removed Needs More Info The issue still hasn't been fully clarified labels Jan 20, 2022
@ahejlsberg
Copy link
Member

Issue no longer reproduces, looks like it was fixed in 5.1.

@ahejlsberg ahejlsberg added Fixed A PR has been merged for this issue and removed Needs Investigation This issue needs a team member to investigate its status. labels Mar 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

4 participants