Skip to content

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

Closed
falsandtru opened this issue Jun 5, 2018 · 6 comments
Closed

Method argument types aren't inferred from mapped types #24694

falsandtru opened this issue Jun 5, 2018 · 6 comments
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@falsandtru
Copy link
Contributor

TypeScript Version: master

Search Terms:

Code

declare function f<T extends object>(data: T, handlers: { [P in keyof T]: (value: T[P], prop: P) => void; }): void;
f({ data: 0 }, {
  data(value, key) {
  },
});

Should also work with optional.

declare function f<T extends object>(data: T, handlers: { [P in keyof T]?: (value: T[P], prop: P) => void; }): void;
f({ data: 0 }, {
  data(value, key) {
  },
});

Expected behavior:

pass

Actual behavior:

$ node built/local/tsc.js --strictNullChecks --noImplicitAny index.ts
index.ts:3:8 - error TS7006: Parameter 'value' implicitly has an 'any' type.

3   data(value, key) {
         ~~~~~


index.ts:3:15 - error TS7006: Parameter 'key' implicitly has an 'any' type.

3   data(value, key) {
                ~~~

Playground Link:

Related Issues:

@falsandtru falsandtru changed the title Method signatures won't be reflected mapped types Mapped types won't be reflected method signatures Jun 5, 2018
@falsandtru falsandtru changed the title Mapped types won't be reflected method signatures Method signatures don't reflect mapped types Jun 6, 2018
@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Jun 6, 2018
@falsandtru falsandtru changed the title Method signatures don't reflect mapped types Methods don't infer my own parameter types from mapped types Jun 6, 2018
@falsandtru falsandtru changed the title Methods don't infer my own parameter types from mapped types Methods don't infer my own argument types from mapped types Jun 6, 2018
@falsandtru
Copy link
Contributor Author

@weswigham Can you take a look? Data binding is popular usage.

@mattmccutchen
Copy link
Contributor

What I believe is the same issue came up again in this StackOverflow question.

@mattmccutchen
Copy link
Contributor

I have a patch that fixes this issue but is causing other test failures. Working on it...

@mattmccutchen
Copy link
Contributor

There, I fixed it: #27586.

@yortus
Copy link
Contributor

yortus commented Oct 11, 2018

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'

Playground link

mattmccutchen added a commit to mattmccutchen/TypeScript that referenced this issue Oct 12, 2018
The changes to existing baselines look acceptable to me.

Fixes microsoft#24694.
@falsandtru
Copy link
Contributor Author

Today, language service provides correct info:

(property) data: (value: number, prop: "data") => void

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.

@falsandtru falsandtru changed the title Methods don't infer my own argument types from mapped types Method argument types aren't inferred from mapped types Feb 8, 2019
weswigham pushed a commit that referenced this issue Mar 12, 2019
…7586)

* Handle generic mapped types in getTypeOfPropertyOfContextualType.

The changes to existing baselines look acceptable to me.

Fixes #24694.

* Minor reorganization, add test case from @yortus
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

5 participants