-
Notifications
You must be signed in to change notification settings - Fork 12.3k
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
Equivalent arguments typed with tuples aren't assignable to the same functions with overloads when the same function is recursively referenced #45466
Comments
The example as presented is undecidable, thus rejected. Demonstrated: type START = 0
type DATA = 1
type Args<In, Out> =
| [t: START, other: FnWithArgs<Out, In>]
| [t: DATA]
type FnWithArgs<In, Out> = (...args: Args<In, Out>) => void
type FnWithOverloads<In, Out> = {
(t: START, other: FnWithOverloads<Out, In>): void;
(t: DATA): void;
}
declare const withArgs: FnWithArgs<1, 2>
// Demonstrated: legal call
withArgs(0, withArgs);
// Asserted: This should be legal (use 'as any')
const assertion: FnWithOverloads<1, 2> = withArgs as any;
// Illegal call: 'withArgs' is not a substitute for 'assertion'
assertion(0, withArgs); The last line is legal if and only if |
I'm sorry @RyanCavanaugh, I'm having trouble comprehending your example. In my eyes, it further demonstrates that the issue I described exists, i.e. I understand that resolving // this is ok:
assertion(0, assertion);
// this is also ok:
withArgs(0, withArgs);
// and this SHOULD be okay, but isn't:
withArgs(0, assertion);
// the other way SHOULD also be okay (your example):
assertion(0, withArgs) |
It seems I've overthought this. The simplest form doesn't work: type Overloaded = {
(n: number): void;
(s: string): void;
}
type Tupled = {
(...args: [number] | [string]): void;
}
let x: Overloaded = null as any as Tupled;
let y: Tupled = null as any as Overloaded; |
Are those actually equivalent? I ask because: const stuff: [number] | [string] = [ 812 ] as any;
tupled(...stuff); // okay
overloaded(...stuff); // error! The root of the issue seems to be that TS wants to be able to "choose" a specific overload (even though it's going to be the same underlying function being called at runtime), while this decision doesn't need to be made for the tuple case. So they are not equivalent, even though they are. |
This is a correct analysis of what's going wrong, but also a frequent source of complaint. Barring the problems of combinatorial explosion, this "should" work but doesn't. |
Thanks @RyanCavanaugh, this is exactly the issue I was referring to! I noticed the label "Awaiting More Feedback", may I ask what type of feedback is expected? Or does this refer to some internal process? |
It means we’d like to see how many people 👍 this issue and comment with other solutions and ideas before considering it more. |
Bug Report
🔎 Search Terms
arguments, overloads, function, tuple
🕗 Version & Regression Information
All versions with support for tuple arguments (upto v4.5.0-dev.20210815).
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
Two types that should be functionally equivalent aren't assignable to one another:
I've tried simplifying the example, and this issue doesn't seem to occur when the parameters of the function don't reference themselves in their signature.
🙂 Expected behavior
No error, types should be assignable to one another.
Related issues
The text was updated successfully, but these errors were encountered: