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

Unexpected union inference because of generic function argument #16107

Closed
gcnew opened this issue May 26, 2017 · 3 comments
Closed

Unexpected union inference because of generic function argument #16107

gcnew opened this issue May 26, 2017 · 3 comments
Assignees
Labels
Breaking Change Would introduce errors in existing code Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@gcnew
Copy link
Contributor

gcnew commented May 26, 2017

TypeScript Version: nightly (2.4.0-dev.20170502)

TypeScript improperly infers a union type when a generic function is used as an argument. Such an inference is unexpected unless the union constituent is present, or the type arguments are manually provided by the programmer.

Code

declare function sameType<T>(x: T, y: T): T;
declare function test<R>(f: (x: string, y: number) => R): void;

test(sameType); // bad inference: R = string | number
@ahejlsberg
Copy link
Member

I'm not sure I see why inferring a union type is incorrect. After all, there are no declared constraints on T and it is indeed possible to pass sameType to test with the inferred union type argument. I agree that in a general unification scenario (e.g. where sameType and test are both passed as arguments to a third function) we probably wouldn't want to infer a union, however in this particular case we know that we're inferring types for one in terms of the other (but not vice versa).

@gcnew
Copy link
Contributor Author

gcnew commented Jun 9, 2017

Because by having a type argument, the expectation for it is to be resolved to a single type. I think I've read it somewhere in the docs that type inference doesn't create types and it doesn't infer unions unless they are provided by the programmer. If that were not the case, how would a type variable be constrained to a single type?

It seems counter intuitive to me for a function such as sameType, which states that x and y have the same type, to be circumvented by saying "they have the same synthetic union type". If I didn't need x and y to have the same type, I would have used different type variables.

PS: The current behaviour creates some discrepancies. E.g. a variation of the example from #138:

declare var f: <R>(s: string, n: number) => R;
declare var g: <T>(x: T, y: T) => T;
f = g; // good, error with #16368

declare function test1(h: typeof f): void;
declare function test2<R>(h: (s: string, n: number) => R): void;
test1(g); // good, error with #16368
test2(g); // no error? how is this different from test1

Edit: I've been wrong, test1 and test2 are substantially different. The expanded signature of test1 is

declare function test1(h: <R>(s: string, n: number) => R): void;

Here, the type parameter R is universally quantified, i.e. test1 accepts a function h, which should be able to return any possible type. When we pass in g as an argument, it will simply return its first argument, which is incorrect.

In test2 the type parameter R is existentially quantified in regards to h.

@gcnew
Copy link
Contributor Author

gcnew commented Jun 10, 2017

I'm not sure I can give a more convincing example. Type variables are inferred to a single type in all locations except for function arguments. And even there it's not always the case as the code from my previous comment shows. I believe that generic inference behaviour should be uniform across all uses.

declare function test3<R>(x: R, y: R): void;
declare function test4<R>(h: (s: string, n: number) => R, x: R, y: R): void;

test3(3, 'str'); // good, error with #16368
test4(g, 3, 'str'); // no error :(, what's changed? 

@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Aug 29, 2017
@mhegazy mhegazy added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Feb 2, 2018
@mhegazy mhegazy added this to the TypeScript 2.9 milestone Apr 12, 2018
@mhegazy mhegazy modified the milestones: TypeScript 3.0, TypeScript 3.1 Jul 2, 2018
@RyanCavanaugh RyanCavanaugh added the Breaking Change Would introduce errors in existing code label Aug 29, 2018
@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Aug 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

No branches or pull requests

4 participants