Repository navigation
[5.4 regression] Broken relation of deferred index type over a mapped type on the source side #57188
Description
Activity
RyanCavanaugh commented
on Feb 1, 2024 MemberMore actionsCan we get a smaller repro? 👀
Lol. That's a crazy long repro.
When trying to understand what's going on, I found that
keyof Invert<Record<string,string>>is notstring#57265 but I don't know if this is related to the root cause.I also found that changing the definition of
Casttotype Cast<A, B> = A extends B ? (A&B) : B;does resolve the issue (though notably in v5.4.0-dev.20240110 and NOT in v5.4.0-dev.20240201)Andarist commented
on Feb 2, 2024 ContributorAuthorMore actionsThe best I can get now is this: TS playground. I doesn't minimize it by a lot though. At this point almost everything that I remove makes the error go away.
That said, I will investigate this within the internals and compare the current and old execution paths to learn more about this. That might make it possible for me to create a smaller repro. I just need to find some time for this deep dive.
- addedNeeds More InfoThe issue still hasn't been fully clarifiedThe issue still hasn't been fully clarified
on Feb 2, 2024 Andarist commented
on Feb 5, 2024 ContributorAuthorMore actionsIt turns out that #56742 isn't exactly the culprit here. I think that once it landed it led to some weird situation in which it errored incorrectly (
Castshould make TS happy here regardless of other things). However, since there was another problem in TS at that time - I don't think it's worth investigating further.The additional problem was this incorrect PR of mine ( #57202 ) that was recently reverted here #57202 . We can go back to TS 5.0 (that predates the PR that was reverted) to see a different error: TS playground
What happens here is that the base constraint of
Invert<TChildrenMap>can't be computed because it is a generic mapped type with a generic index type. So TS determines that this has a circular base constraint. So in the end, it can't validate thatInvert<TChildrenMap>[K](with the constraint ofInvert<TChildrenMap>[string]) is assignable tostring | undefined.It's known that
Khas to be a string (it has a constraint ofkeyof TActors & string) and that values ofInvert<TChildrenMap>arestring. So it looked like it could be able to figure out that this has astringconstraint but it turns out that it can't.The fix for this is straightforward on my side. I can introduce a temporary infer type variable (
Invert<TChildrenMap> extends infer TInverted) and use that in my checks: TS playgroundit is kinda cheating here because it doesn't really fix the base constraint of the
invertthing. It's still generic, right? But since infer type variables often "forget" about their original constraints I can abuse it here (I'm sorry!).TInverted's constraint isunknown,keyof unknownisneverandneveris assignable to everything. So by introducing it, TS ends up checking smth along those lines:type Target = string | undefined type Source = Invert<TChildrenMap> extends infer TInverted ? keyof TActors & string extends keyof TInverted ? TInverted[keyof TInverted & keyof TActors & string] : string | undefined : never type SourceConstraint = keyof TActors & string extends never ? never : string | undefined type Result = SourceConstraint extends Target ? 1 : 0 // 1
Alternatively, I can just add
& stringtoInvert<TChildrenMap>[K]to fix this constraint problem: TS playground. That's probably what I will go with here 😉Case closed.
🔎 Search Terms
deferred index mapped type apparent keys
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play?noErrorTruncation=true&ts=5.4.0-dev.20240110#code/PTAEAEDsHsFECd7XgFXgV0gYwIYBcBLaSALlDwwFMAoPATwAdLQA1HAG3UoGcAeFAHygAvKBQBtANaU60AGZiAugG5ajZgEluAOUoA3SvH5DR4lItCUAHnkqQAJt1DjI+wxYD85KqDJyO3JSq9EygAMI43Hi8AIIANKAAQiagMZY2do5JoF5pZInB6uHQALYM6Lax6bYOTjiQdCkA3s4A0qAEkKDSsgoximQx4q0WAL6gAGSgmJIwAO6QhaEakAbw0SjVmU4ASpRYyPa8AApITOt0rTIJp9Dn9FeNzdSgbR1dPfJioJFiw4oDUCtVSjVTUTq2eD+LDMGJYPDIAAy0AA5gQsLxOqBoBUxABlSA4BjcAAW0DwCSxOLwYlgBkgNOsNSyLRClDIUXgnRRoFGQiaL289W4BEIxDIAApuITiWS8GQUASiaTyQkSjxuDgUezafS8ABKERCRUylV4EHUNShGINOEI+DItFYESpeFI1Ho3j1OgJb0CMEQwzQ2Fu+B7OT8JWy1W6uyMjK1UCs9Qcijc3n8wWBByStwMhV0uOG4RCPTQAj2VSvbV4KNmyXF411uUWq2w22h8Muu3IcNehq+hr+y1s1328MAMSQJWMLs2TO2Y-dTsxkDkhnxprllLXG5QhYZAkFuU7lAjJuV29jh8FZFcawDDKDOBhoFuegrlHsPfgSaz8CwVMuUgFEq1AdgPUA1IO3tR10TAisPCA7lW3sfZ2BweBmCwDDuCcPE8HwSgAFkXxJTpKF4QUUDCcj2HsLCugXRM9gOeAjk5bkEhtOgfy7AAfaYHDPCj7AEOJqEzV4sDohi7AVWiCHoxjW1HWAbHgF88ERUVDA4AjgJRfgtkTTiQNAQTMDQuRRJSecEyyMyUWPUAnJMrIUEFV4vHvQwvN8MRb1AXz4DBUcUGgMJiCwLDbEU5S7H4H93Kcd9P2-UNnlecQ0ixFBkt+dSKC0nTIX0tMQNicQACIK2qxQBEUJClzDM8p1KKrqogp16uHUERyKCL4rkyAktDFK3yQD80Iy+0Ujc5iPJ-GruAA+qXNYw5eCc7iYN7M8j1eMgorKCpKP814hui2LKGGxixrmyYLteP8Xrel7Ohw9A0LIAV3v+5wK2QkDAXy8bFrqBpnoBnIWsnacHuQGruvRXqLKE6zROhgG7zcULsdefqYdeawvp+pMiYB0ZxCskTXHsCawftGq6osAnYdq7BODQ6r2eBnkIbEZbavsdbiY5z7ucoXnxbIarSalsWXuHNsxGgNKZp-KjLruuxSIYCbNvY7aKpRBInPE6ifycQWjaONhOB4fhdcgfXxOg3jQzgrBLZSB2uD4P63ixT4FCZ5AnCmJzASD15Vqg4F-JRqDw-gbh-jA14gdALRdDWZ3ZMYt2JooLhnq8NzLOEmz6eesh2kF0Oc9WQwNhdt3y+btY28LvWiQEf469c030dpmuvzA-q+TBNCcMw5g5EweEiC6QI8HQBhtaF0MbYc3Z9i2-2nZo3vXf73bPdgyDLZ10-9cNg-jZ24fDJSEKJIECUg60iOJNGX7BRsm4M1WOoAZJKRGs1E+ECi5EknmBH+acQH+WGO8boMgvip24KDa2GdBRT31AA6SWEiKkXAa4BsRpQAEVIWRCiW9XgRCiAwl6Q1T78HVlNdKWtoEJTPgwBIWCBA33enbE2hkL58TPKPautl-KHVAH1VQQA
💻 Code
🙁 Actual behavior
It fails to be checked
🙂 Expected behavior
The used
Castshould be enough to satisfy the constraintAdditional information about the issue
We can get rid off the error (but lose functionality):
idfromToProvidedActorComputefromToChildrenComputeExtractLiteralStringfilter~ fromToConcreteChildrencc Wesley Wigham (@weswigham) (since it's a change from #56742 )