-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Method argument types aren't inferred from mapped types #24694
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
@weswigham Can you take a look? Data binding is popular usage. |
What I believe is the same issue came up again in this StackOverflow question. |
I have a patch that fixes this issue but is causing other test failures. Working on it... |
There, I fixed it: #27586. |
Our codebase runs into this compiler limitation. While investigating the root cause, I came up with a bunch of cases that I expected all to compile without errors, but half fail because of the lack of contextual typing as described in the OP. I'll paste my repro here in case it's useful to add to the compiler tests (eg in @mattmccutchen's PR). type TakeString = (s: string) => any;
// Various functions accepting an object whose properties are TakeString functions.
// Note these all use mapped types.
declare function mapped1<T extends {[P in string]: TakeString}>(obj: T): void;
declare function mapped2<T extends {[P in keyof T]: TakeString}>(obj: T): void;
declare function mapped3<T extends {[P in keyof any]: TakeString}>(obj: T): void;
declare function mapped4<T>(obj: T & {[P in keyof T]: TakeString}): void;
declare function mapped5<T, K extends keyof T>(obj: T & {[P in K]: TakeString}): void;
declare function mapped6<K extends string>(obj: {[P in K]: TakeString}): void;
declare function mapped7<K extends keyof any>(obj: {[P in K]: TakeString}): void;
declare function mapped8<K extends 'foo'>(obj: {[P in K]: TakeString}): void;
declare function mapped9<K extends 'foo'|'bar'>(obj: {[P in K]: TakeString}): void;
// Expected: no errors. Actual: half work, half don't.
mapped1({foo: s => 42}); // OK: 's' is contextually typed as 'string'
mapped2({foo: s => 42}); // ERROR: Parameter 's' implicitly has an 'any' type
mapped3({foo: s => 42}); // OK: 's' is contextually typed as 'string'
mapped4({foo: s => 42}); // ERROR: Parameter 's' implicitly has an 'any' type
mapped5({foo: s => 42}); // OK: 's' is contextually typed as 'string'
mapped6({foo: s => 42}); // ERROR: Parameter 's' implicitly has an 'any' type
mapped7({foo: s => 42}); // OK: 's' is contextually typed as 'string'
mapped8({foo: s => 42}); // ERROR: Parameter 's' implicitly has an 'any' type
mapped9({foo: s => 42}); // OK: 's' is contextually typed as 'string' |
The changes to existing baselines look acceptable to me. Fixes microsoft#24694.
Today, language service provides correct info:
But oddly it is not reflected in type inference and type checking. @weswigham @ahejlsberg Can you infer types like that info? I'm not sure why such difference is allowed. #29409 is another similar case. |
TypeScript Version: master
Search Terms:
Code
Should also work with optional.
Expected behavior:
pass
Actual behavior:
Playground Link:
Related Issues:
The text was updated successfully, but these errors were encountered: