-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Generic function with rest parameter assignability not transitive #32948
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
Comments
Assignability has never been transitive - see The examples I gave in the thread you discovered it is more compelling - two nearly identical types (identical sans alias symbol) that do not yield identical comparison results. |
Guess I'll include the no-alias version for completeness, /**
* --strictFunctionTypes
*/
export type ExtendedMapper<HandledInputT, OutputT, ArgsT extends any[]> = (
//Using the no-alias example from,
//https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521930291
{x:(name : string, mixed : HandledInputT, ...args : ArgsT) => OutputT}["x"]
);
//type a = (name: string, mixed: any, args_0: any) => any
type a = ExtendedMapper<any, any, [any]>;
//type b = (name: string, mixed: any, ...args: any[]) => any
type b = ExtendedMapper<any, any, any[]>;
//3.5.1, [email protected]
//Expected: "y"
//Actual : "y"
//https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
//https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/40404/artifacts?artifactName=tgz&fileId=AD9D22CF70561BEAF5758E061B61D3FF891ADF664E37C532F5881393CE7DC83202&fileName=/typescript-3.7.0-insiders.20190815.tgz
//Expected: "y"
//Actual : "y" <-- Using the "no-alias" example, it works as intended
type test = a extends b ? "y" : "n"
type a2 = (name: string, mixed: any, args_0: any) => any
type b2 = (name: string, mixed: any, ...args: any[]) => any
//3.5.1, [email protected]
//Expected: "y"
//Actual : "y"
//https://github.com/microsoft/TypeScript/pull/32924#issuecomment-521819476
//https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/40404/artifacts?artifactName=tgz&fileId=AD9D22CF70561BEAF5758E061B61D3FF891ADF664E37C532F5881393CE7DC83202&fileName=/typescript-3.7.0-insiders.20190815.tgz
//Expected: "y"
//Actual : "y"
type test2 = a2 extends b2 ? "y" : "n" It's weird to me that the no-alias version behaves as expected. That partial object assignability not being transitive makes sense. I forgot about that =x |
I think this stems from the special rules for const list: any[] = [];
const tuple: [any] = list;
const fn: (...args: any[]) => void = undefined as any as (...args: [any]) => void; A list of type The type alias does not track the context in which a type parameter was used so checking uses the first relationship, rather than the second. |
You say this is a "special rule" but... isn't that just a natural consequence of contravariance? |
The assignment to While the function assignment is allowed, a corresponding assignment of identifiers of those types would not be. A correction in my wording: the special treatment does not apply specifically for This is effectively the same problem as #31698; specifically see this comment here. |
Right, what I was getting at was it was it was the same as how ...unless you mean this applies at the time the function is called? |
The special treatment is that the normal rules of contravariance of function input are ignored in this particular case. Using the normals rules would suggest than assigning a function that expects a more precise arity (exactly one) to a function that expects a less precise arity (0 or more) would be an error. const echo = (x: string) => console.log(x);
const fn: (...args: string[]) => void = echo; // no error
fn(); // no error, but echo is called without an argument; However, the checker will not complain here because it assumes that |
Oh I see, it can lead to unsound calls. That makes sense now. I admit I hadn't considered the effect of the rest parameter on the function's arity (there's a word you don't see often!): I just saw that clearly, you can use a function that accepts a Thanks for being patient with me, I feel pretty dumb now. 🥴 |
@fatcerberus Any time - good questions and discussion make the tracker better for everyone that uses it. |
Uh oh!
There was an error while loading. Please reload this page.
TypeScript Version:
https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/40404/artifacts?artifactName=tgz&fileId=AD9D22CF70561BEAF5758E061B61D3FF891ADF664E37C532F5881393CE7DC83202&fileName=/typescript-3.7.0-insiders.20190815.tgz
Search Terms:
Code
Expected behavior:
Build in #32924 (comment) should behave the same as 3.5.1 and [email protected]
Assignability should be transitive.
a -> b2 -> b should imply a -> b
Actual behavior:
Assignability is not transitive
a -> b2 -> b but not a -> b
Playground Link:
Playground
Related Issues:
#32924 (comment)
#32924 (comment)
#32924 (comment)
I'm not sure which commit introduced this problem.
@weswigham
The text was updated successfully, but these errors were encountered: