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
exportfunctionkeyOf<a>(value: {key: a;}): a{returnvalue.key;}exportinterfaceData{key: number;value: Date;}vardata: Data[]=[];exportfunctiontoKeys<a>(values: a[],toKey: (value: a)=>string): string[]{returnundefined;}toKeys(data,keyOf);// <-- actual ok, expected error, since `keyOf` should be inferred as `number` rather than `string`
This actually behaves according to spec. We instantiate the generic keyOf function during type inference (to facilitate making further type inferences from it's return type), but for purposes of assignment compatibility we substitute type any for all type parameters. This behavior has been in place since 1.0. We went that way because of infinite recursion issues relating to contextual signature instantiation with Promises for which we never found meaningful solutions.
I understand that inference can be really hard. What I don't understand is why instead of displaying an error message saying it that inference cannot be done, you decided to go a simpler way that somehow compiles making code unsound and leading to nasty bugs.
I think we are conflating some concepts here. The inference itself succeeds, as it should. In your example, number is the result of the inference. However, the assignability check succeeds unsoundly. As Anders Hejlsberg (@ahejlsberg) explained, the original reason for this unsoundness is indeed that historically, checking this in a sound way led to an infinite recursion. But we have a new way of dealing with infinite recursion that would be resilient to this sound way of checking signatures. So in theory, we could check this in a way that would fail, using contextual signature instantiation.
Jason Freeman (@JsonFreeman), so now that you say you have that new way round that infinite recursion problem, do you think we should reopen this issue or the other related one that got closed too #3055?
not sure what it means when you guys close valid issue reports
In the past, when we had this behavior, we found that many people were confused by it, and it disallowed lots of code that seemed reasonable even though the code was technically not sound. Also, generic signatures that are part of generic types do lead to this deep recursion, and even though we have a way of limiting the depth of the recursion, it would still deepen the assignability checks drastically and make assignability checks take much longer. So while there are no longer technical limitations in the way, fixing this would seem to hamper most users' experiences more than it would benefit them.
I'd say this falls into the category of checks explored by #274. Ryan Cavanaugh (@RyanCavanaugh), is that issue a good meter for the popularity of a "stricter" mode?
will there be an infinite recursion still if TS replaces point free notation , toKeyOf with an explicit lambda , x => keyOf(x) behind the scene during compiling?
This happens for the same reason discussed above. The a in keyOf is replaced by any during assignability checks. The reason it works in the explicit lambda case is because the lambda is not generic. So a generic function keyOf is replaced with a non-generic function that makes the inference explicit.
I agree this is not intuitive. Again, I think this qualifies as a good feature for stricter type checking, though arguably it should be part of the basic type check mode as well.
Jason Freeman (@JsonFreeman) I vote with two hands for the stricter type checking mode. As far as I know, non strict type checking in TypeScript was one of the reason why Facebook/Flow was created.
Activity
RyanCavanaugh commentedon May 5, 2015
Simplifying this somewhat:
Paging Jason Freeman (@JsonFreeman)
ahejlsberg commentedon May 6, 2015
This actually behaves according to spec. We instantiate the generic
keyOffunction during type inference (to facilitate making further type inferences from it's return type), but for purposes of assignment compatibility we substitute typeanyfor all type parameters. This behavior has been in place since 1.0. We went that way because of infinite recursion issues relating to contextual signature instantiation with Promises for which we never found meaningful solutions.zpdDG4gta8XKpMCd commentedon May 6, 2015
I understand that inference can be really hard. What I don't understand is why instead of displaying an error message saying it that inference cannot be done, you decided to go a simpler way that somehow compiles making code unsound and leading to nasty bugs.
Are there any plans to fix it?
JsonFreeman commentedon May 6, 2015
I think we are conflating some concepts here. The inference itself succeeds, as it should. In your example, number is the result of the inference. However, the assignability check succeeds unsoundly. As Anders Hejlsberg (@ahejlsberg) explained, the original reason for this unsoundness is indeed that historically, checking this in a sound way led to an infinite recursion. But we have a new way of dealing with infinite recursion that would be resilient to this sound way of checking signatures. So in theory, we could check this in a way that would fail, using contextual signature instantiation.
zpdDG4gta8XKpMCd commentedon May 7, 2015
Jason Freeman (@JsonFreeman), so now that you say you have that new way round that infinite recursion problem, do you think we should reopen this issue or the other related one that got closed too #3055?
not sure what it means when you guys close valid issue reports
JsonFreeman commentedon May 7, 2015
In the past, when we had this behavior, we found that many people were confused by it, and it disallowed lots of code that seemed reasonable even though the code was technically not sound. Also, generic signatures that are part of generic types do lead to this deep recursion, and even though we have a way of limiting the depth of the recursion, it would still deepen the assignability checks drastically and make assignability checks take much longer. So while there are no longer technical limitations in the way, fixing this would seem to hamper most users' experiences more than it would benefit them.
zpdDG4gta8XKpMCd commentedon May 7, 2015
Is there a reason (besides budget) for not having an option to instruct the compiler to do thorough checks?
JsonFreeman commentedon May 7, 2015
I'd say this falls into the category of checks explored by #274. Ryan Cavanaugh (@RyanCavanaugh), is that issue a good meter for the popularity of a "stricter" mode?
danquirk commentedon May 8, 2015
Aleksey-Bykov Feel free to add a comment in that issue with a small description or link to this issue as far as an additional check.
zpdDG4gta8XKpMCd commentedon Oct 11, 2016
gentlemen, how come the following work?
zpdDG4gta8XKpMCd commentedon Oct 11, 2016
will there be an infinite recursion still if TS replaces point free notation
, toKeyOfwith an explicit lambda, x => keyOf(x)behind the scene during compiling?JsonFreeman commentedon Oct 11, 2016
This happens for the same reason discussed above. The
ainkeyOfis replaced byanyduring assignability checks. The reason it works in the explicit lambda case is because the lambda is not generic. So a generic functionkeyOfis replaced with a non-generic function that makes the inference explicit.I agree this is not intuitive. Again, I think this qualifies as a good feature for stricter type checking, though arguably it should be part of the basic type check mode as well.
sergey-shandar commentedon Oct 11, 2016
Jason Freeman (@JsonFreeman) I vote with two hands for the stricter type checking mode. As far as I know, non strict type checking in TypeScript was one of the reason why Facebook/Flow was created.
ahejlsberg commentedon Mar 8, 2019
Fixed in #30215.