Skip to content
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

Generic type not bound from return value of parameter #13346

Closed
danvk opened this issue Jan 7, 2017 · 4 comments
Closed

Generic type not bound from return value of parameter #13346

danvk opened this issue Jan 7, 2017 · 4 comments
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@danvk
Copy link
Contributor

danvk commented Jan 7, 2017

I'm trying to model the underscore / lodash chain method and running into an odd issue.

TypeScript Version: 2.1.4

Code

interface Chainable<T> {
  value(): T;
  mapValues<U>(func: (v: T[keyof T]) => U): Chainable<{[k in keyof T]: U}>;
}

declare function chain<T>(t: T): Chainable<T>;

const square = (x: number) => x * x;

const v = chain({a: 1, b: 2}).mapValues(square).value();

Expected behavior:

v should have type {a: number, b: number}.

Actual behavior:

v has type {a: U, b: U}.

It's not even really clear to me what U means in this context. TS knows that the type of square is (x: number) => number, so it should be able to deduce that U in mapValues must be number.

What's more, even if I make U explicit:

const v = chain({a: 1, b: 2}).mapValues<number>(square).value();

then v still comes out with a type of {a: U, b: U}.

@aluanhaddad
Copy link
Contributor

try

  mapValues<U, K extends keyof T>(func: (v: T[K]) => U): Chainable<{[P in K]: U}>;

@danvk
Copy link
Contributor Author

danvk commented Jan 7, 2017

@aluanhaddad that does the trick, thanks.

Why does this work when my approach did not? And should I close this out?

@aluanhaddad
Copy link
Contributor

I'm not 100% sure but I believe this is because as discussed #12342 (comment) and the following comments

mapValues<U>(func: (v: T[keyof T]) => U): Chainable<{[K in keyof T]: U}>;

does not specify a particular generic instantiation that correlates the type of the keys in the resulting type to the keys mapped by func because mapped types are not an inference sites.

There is nothing tying the generic instantiation of T for some keyof T to the result type.
I could be completely wrong 😓

@ahejlsberg
Copy link
Member

This is a bug. Type parameters should never "leak" out of instantiations.

@ahejlsberg ahejlsberg added the Bug A bug in TypeScript label Jan 8, 2017
@ahejlsberg ahejlsberg self-assigned this Jan 8, 2017
@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Jan 8, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

3 participants