You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Generic type arguments not inferred, default to {} #5884
I sometimes run into scenarios where it's clear to me what a generic type argument should be, but typescript fails to infer it. I think this is because inference only looks at the call site, and not the context. The example I just ran into was this:
In the last case it infers type parameter A to {}, causing it to fail since {} has no property foo. But from the context (comparing should return a function (x : { foo : string }, y : { foo : string }) : number) because it is used as an argument to sort on x) it should be clear that A should be { foo : string }.
Is there any way this kind of inference could be added, or is this too complicated due to overloads/subtyping/etc.
P.S. There seem to be several issues about things like this, but they all seem slightly different. If they're not, my apologies. I'd like to have a place where I can track this issue, so I would appreciate any pointers to another ticket, a FAQ, etc.
TypeScript doesn't crave up type arguments from the context. Type parameters of compare can only be resolved from its argument (function f). In the last case there is nothing said about the types of the o => o.foo lambda used as an argument f, so compare has nothing to deduce its type arguments from, so the inference fails.
The question remains why a function declaration defaults its parameters to implicit any whereas parameters of a lambda default to the empty type {}.
Yes, that's what I gathered, and why I asked if that could be changed so the context influences the type inference. This is what I'm used to from e.g. Haskell but of course typescript has many features that make this more complicated.
Hindley-Milner type system as in Haskell doesn't work very well with subtyping and inheritance, also the union type is problematic to work with, so it seems it was a trade-off that TypeScript design team had to make
I don't pass anything to Promise.resolve(), therefore the type argument should be the type of undefined, which in typescript is void. But Typescript defaults it to {}. Doing this however works:
Felix Becker (@felixfbecker)undefined is widened to the type any on inference, which is compatible with void. Passing no arguments means we have no inference sites to guess the generic argument, so we infer to {} - the empty object, which is not compatible with void.
That's how and why it works as it does in your case.
Wesley Wigham (@weswigham) thanks for your answer, but I think this is wrong behaviour... Why the empty object? If I don't pass an argument to a function, the value of that argument will in fact be undefined in the scope of the function, not an empty object. So TS should infer void.
Felix Becker (@felixfbecker) the behavior of inferring {} occurs whenever there are zero inference sites. That can happen for a number of reasons, not just because there aren't any arguments being passed.
Activity
zpdDG4gta8XKpMCd commentedon Dec 2, 2015
TypeScript doesn't crave up type arguments from the context. Type parameters of
comparecan only be resolved from its argument (functionf). In the last case there is nothing said about the types of theo => o.foolambda used as an argumentf, socomparehas nothing to deduce its type arguments from, so the inference fails.The question remains why a function declaration defaults its parameters to implicit
anywhereas parameters of a lambda default to the empty type{}.hesselink commentedon Dec 2, 2015
Yes, that's what I gathered, and why I asked if that could be changed so the context influences the type inference. This is what I'm used to from e.g. Haskell but of course typescript has many features that make this more complicated.
zpdDG4gta8XKpMCd commentedon Dec 2, 2015
Hindley-Milner type system as in Haskell doesn't work very well with subtyping and inheritance, also the union type is problematic to work with, so it seems it was a trade-off that TypeScript design team had to make
http://stackoverflow.com/questions/7234095/why-is-scalas-type-inference-not-as-powerful-as-haskells
hesselink commentedon Dec 2, 2015
Yes, that's what I was afraid of. I'm still hoping there is a way to do something local (but less local than now) to get cases like this working.
felixfbecker commentedon Dec 21, 2015
I have that problem frequently with promises. If you write
TypeScript errors with
Type Promise<void> is not compatible with type Promise<{}>.Where does it get the {} from? Definition:
I don't pass anything to Promise.resolve(), therefore the type argument should be the type of
undefined, which in typescript isvoid. But Typescript defaults it to{}. Doing this however works:weswigham commentedon Dec 21, 2015
Felix Becker (@felixfbecker)
undefinedis widened to the typeanyon inference, which is compatible withvoid. Passing no arguments means we have no inference sites to guess the generic argument, so we infer to{}- the empty object, which is not compatible withvoid.That's how and why it works as it does in your case.
to manually specify the type argument, rather than relying on inference may be more along the lines of what you want.
felixfbecker commentedon Dec 21, 2015
Wesley Wigham (@weswigham) thanks for your answer, but I think this is wrong behaviour... Why the empty object? If I don't pass an argument to a function, the value of that argument will in fact be
undefinedin the scope of the function, not an empty object. So TS should infervoid.RyanCavanaugh commentedon Dec 21, 2015
Felix Becker (@felixfbecker) the behavior of inferring
{}occurs whenever there are zero inference sites. That can happen for a number of reasons, not just because there aren't any arguments being passed.DanielRosenwasser commentedon Dec 28, 2015
Discussion should either continue here or on #5254.
mhegazy commentedon Jan 7, 2016
closing this in favor of #5254.
Fix type error in PlayerIcon. The type system is not able to infer th…