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

Contextual type inference fails in surprising case #25814

Closed
bterlson opened this issue Jul 20, 2018 · 4 comments
Closed

Contextual type inference fails in surprising case #25814

bterlson opened this issue Jul 20, 2018 · 4 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Fixed A PR has been merged for this issue

Comments

@bterlson
Copy link
Member

bterlson commented Jul 20, 2018

TypeScript Version: 3.1.0-dev.20180719
Code

type R = {
  a: (x: number) => void;
  b: (x: string) => void;
};

type O = {
  on<P extends keyof R>(x: P, callback: R[P]): void;
};

declare var x: O;
x.on('a', a => {}); // not contextually typed.

Expected behavior:
Contextually type a to number.

Actual behavior:
A is not contextually typed, while signature help gives the correct answer.

Playground Link: here

@ahejlsberg
Copy link
Member

This is working as intended (but you could argue a design limitation). We only contextually type function expression parameters when the parameter type is known to be a function type before instantiation. In your example, we would have to fix P following inference for the first argument and then P during inference for the second argument, but we don't do that currently. I suppose you could argue we should if all properties addressable by R[P] are function types, but that would be a new feature.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 20, 2018
@ahejlsberg
Copy link
Member

BTW, it works if you write it like this (because inference now knows the contextual type is a function type):

type R = {
  a: number;
  b: string;
};

type O = {
  on<P extends keyof R>(x: P, callback: (x: R[P]) => void): void;
};

declare var x: O;
x.on('a', a => {}); // Contextually typed.

@bterlson
Copy link
Member Author

I see @ahejlsberg, thanks. Consider this a feature request then 😊

Thank you so much for pointing out it works if the callback is "obviously" a function type, I think I can make this work for my scenario with the following tweak to the OP:

type R = {
  a: (x: number) => void;
  b: (x: string) => void;
};

type O = {
  on<P extends keyof R>(x: P, callback: (...args: Params<R[P]>) => void): void;
};

type Params<F> = F extends (... args: infer T) => any ? T : never;

declare var x: O;
x.on('a', a => {}); // yay is contextually typed now!

@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Mar 28, 2019
@ahejlsberg ahejlsberg added this to the TypeScript 3.5.0 milestone Mar 28, 2019
@ahejlsberg ahejlsberg added Design Limitation Constraints of the existing architecture prevent this from being fixed and removed Working as Intended The behavior described is the intended behavior; this is not a bug labels Mar 28, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

3 participants