Repository navigation
Intra expression inference doesn't work within reverse mapped types #53018
Description
Activity
What is a “reverse mapped type”? I looked at the repro code but that just looks like a regular mapped type to me.
Andarist commented
on Feb 28, 2023 ContributorAuthorMore actionsA reverse mapped type is a type parameter that has to be inferred from usage when the usage is a mapped type - at least that's my mental model around this, this definition doesn't have to be 100% precise. So, here - the
Tis the reversed mapped type (not the mapped type at the argument position). It's called like that because TS has "reverse" the mapped type at the argument position to construct "what thisTcould look like to satisfy this mapped type?". It's how it's called internally in the codebase - take a look at the inferReverseMappedType.Reacted by Bruce Pascoe and Nicky McCurdy- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptExperience EnhancementNoncontroversial enhancementsNoncontroversial enhancements
on Feb 28, 2023 Andarist commented
on Mar 1, 2023 ContributorAuthorMore actionsSo I guess this is related to the umbrella issue here as that is still open. I think though that this one here is more of a bug/unhandled case within the original fix than a new feature request. This umbrella issue stays open because there are still other situations for which the original fix didn't do much but this issue here is very similar to the ones fixed by that PR. I think that those other situations could be put into a "different kind of an expression" category - whereas here we deal with the same types of expressions, they are just contained in a mapped type. Inferring reverse mapped types is implemented sufficiently differently that this still manifests for them.
throwing in a bug recently discovered that appears to be related: playground
looks like an explicit type annotation is needed to keep inference. further, not using an arrow function appears to break it as wellcc @nickmccurdy
Reacted by Nicky McCurdyAndarist commented
on Apr 17, 2023 ContributorAuthorMore actionsfurther, not using an arrow function appears to break it as well
If you mean that it also doesn't work when you use a regular function expression (
async function (request: Request) {}) then it's because such a function is also context-sensitive (just like the unannotated arrow). A regular function expression always has an implicitthisparameter. That's also why it starts to work again when you annotate that parameter:async function (this: undefined, request: Request) {}Reacted by Nicky McCurdyJust building on the possibly related react-query issue, here's a minimal example of that:
For some reason showing up as unknown and not a typechecking error here, but the order does matter.

Bug Report
🔎 Search Terms
intra expression inference reverse mapped type
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code (object variant)
Playground link with relevant code (tuple variant)
💻 Code
🙁 Actual behavior
This kind of inference that was improved in #48538 doesn't work within a reverse mapped type.
🙂 Expected behavior
It should work in the same way as it does outside of the reverse mapped type. The code in the playground is almost literally taken from the 4.7 announcement blog post about this improvement (here). The only difference is that the
produce/consume"pair" is within a property of reverse mapped typePart of the problem is likely in that
inferReverseMappedTypecallsinferTypeswith separateinferenceshere:https://github.dev/microsoft/TypeScript/blob/e2283e99b47942b863d016c65a3e430dca1549b9/src/compiler/checker.ts#L23938-L23939
and that is not linked anyhow to the current inference
contextandinferFromIntraExpressionSitestries to infer this kind of stuff fromcontext.intraExpressionInferenceSites+context.inferencesand the latter won't be present for the computed reverse mapped type inference:https://github.dev/microsoft/TypeScript/blob/e2283e99b47942b863d016c65a3e430dca1549b9/src/compiler/checker.ts#L23756-L23763
However, I also noticed that
inferReverseMappedTypeis not called at all in this case so those inferences for it aren't even gathered in the first place.