-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Incorrect inference of arrow function with intersected mapped type argument under strictFunctionTypes #32664
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
Case 1 correctly produces no error because Case 3 should produce an error because under strict function types the function inputs are related in reverse, and a string indexer is not related to the object with property declare const x: { [x: string]: string; };
const b: { a: string } = x; // error It appears to be Case 2 that is questionable, and is most likely due to variance measurements. I can correctly synthesise the error by using identical but distinct type aliases. type MappedIntersection<T extends {}> = { [P in keyof T]: string } & {};
type MappedRaw1<T extends {}> = { [P in keyof T]: string };
type MappedRaw2<T extends {}> = { [P in keyof T]: string };
// Case 2: No intersection + arrow = succeed
type ToInferArrowNoIntersection<T extends {}> = {
fn: (params: MappedRaw1<T>) => void;
};
type ArrowNoIntersection<T extends ToInferArrowNoIntersection<any>> = void;
declare const case2: ArrowNoIntersection<{
fn: (params: MappedRaw2<{a: 1}>) => void, // error
}>; So what seems to be going on is that in Case 2 the |
Minimal repro: declare const a: MappedIntersection<any>;
declare const b: MappedRaw1<any>;
const zMeasure: MappedRaw1<{x: string}> = b; // no error
const zStructural: MappedRaw2<{x: string}> = b; // error
const zDifferent: MappedRaw2<{x: string}> = a; // error |
Does #32225 fix the issue, I wonder? |
Yeah I wasn't sure if that was merged, but it seems to target the problem! |
I might be wrong somewhere, but aren't Case 1 and Case 3 supposed to be identical? I was under impression that |
Sorta. Outside |
Does it means that by design third case will always fail? Does that also mean that sometime in the future first case will also be failing? I have trouble understanding why describing same underlying JS might fail or succeed based on a choice of syntax. |
@weswigham Seems to be an issue with unreliable markers rather than unmeasurable, if my understanding is correct. Optionality modifiers work ok, but readonly (or none) do not. type MappedRaw1RO<T extends {}> = { readonly [P in keyof T]: string };
type MappedRaw2RO<T extends {}> = { readonly [P in keyof T]: string };
declare const b: MappedRaw1RO<any>;
const zMeasure: MappedRaw1RO<{x: string}> = b; // ***no error***
const zStructural: MappedRaw2RO<{x: string}> = b; // ***error***
type MappedRaw1OPT<T extends {}> = { [P in keyof T]-?: string };
type MappedRaw2OPT<T extends {}> = { [P in keyof T]-?: string };
declare const b2: MappedRaw1OPT<any>;
const zMeasure2: MappedRaw1OPT<{x: string}> = b; // ***error***
const zStructural2: MappedRaw2OPT<{x: string}> = b; // ***error*** |
@jack-williams, if Case 3 indeed should produce an error, check out the case where |
@smoogly The only fully typesafe way to relate two functions is to relate their parameters contravariantly, i.e. function A is assignable to function type B only if all of B's parameters are assignable to A's. This is because the parameters represent data that flows in the opposite direction over the Methods are related bivariantly as a tradeoff, because much of the public JS API (especially the DOM API) have fundamentally unsound designs that would become very difficult to use if the "correct" variance were enforced for methods. For example, |
@smoogly That compiles for the same reason case two compiles: the use of the alias enables variance measurements. The type |
Gentlemen, thank you for setting my mind straight about assignability. |
#32225 doesn't fix this :( |
@weswigham What do unreliable markers do? From a quick glance it seems that they have no affect and only unmeasurable is guaranteed to prevent variance measurements being used. In the most conservative case any use of interface KeyOf<T> {
key_of: keyof T;
}
const x: KeyOf<{ [x: string]: number }> = { key_of: "random" } // also works with KeyOf<any>
const y: KeyOf<{ x: number }> = x;
const xKey: "x" = y.key_of; Aside from ignoring variance when the type parameter is instantiated with a degenerate case like |
|
So |
I would, too, but as it turns out a |
TypeScript Version: 3.6.0-dev.20190801
Search Terms:
inference
intersection type
strictFunctionTypes
Code
Expected behavior:
Expected case 3 to succeed.
Actual behavior:
Case 3 produces:
Seems relevant that compilation succeeds without
strictFunctionTypes
Playground Link: Playground
Related Issues:
#29123 (comment)
#31081
The text was updated successfully, but these errors were encountered: