TypeScript: [NewErrors] 5.4.0-dev.20240121 vs 5.3.3
The following errors were reported by 5.4.0-dev.20240121, but not by 5.3.3 Pipeline that generated this bug Logs for the pipeline run File that generated the pipeline
This run considered 200 popular TS repos from GH (after skipping the top 0).
Successfully analyzed 115 of 200 visited repos
| Outcome | Count |
|---|---|
| Detected interesting changes | 12 |
| Detected no interesting changes | 103 |
| Git clone failed | 3 |
| Package install failed | 35 |
| Project-graph error in old TS | 5 |
| Too many errors in old TS | 38 |
| Unknown failure | 4 |
Investigation Status
| Repo | Errors | Outcome |
|---|---|---|
| BuilderIO/qwik | 2 | #56004, #56598 |
| chakra-ui/chakra-ui | 1 | Not a regression |
| drizzle-team/drizzle-orm | 16 | #56004 |
| heyxyz/hey | 1 | Intentional isolatedModules correctness improvement |
| pixijs/pixijs | 2 | Routine DOM update #57027 |
| prisma/prisma | 10 | Intentional isolatedModules correctness improvement |
| pubkey/rxdb | 3 | #54477, only showed up in editor for some reason |
| quilljs/quill | 3 | Unused ts-expect-error due to #56908, Intentional isolatedModules correctness improvement |
| react-hook-form/react-hook-form | 1 | #56004 |
| reduxjs/react-redux | 2 | #56515 |
| refined-github/refined-github | 5 | #56004 |
| vuejs/core | 3 | #55015, #56004 |
About this issue
- Original URL
- State: closed
- Created 5 months ago
- Comments: 29 (16 by maintainers)
Ok, I now see what’s going on.
The repro checks whether
EPlusFallback<Lowercase<T>>is assignable toEPlusFallback<Keys>(which is just{}).With #56004, the constraint of
EPlusFallback<Lowercase<T>>ends up correctly being typeEMap["event" & Lowercase<T>] | "unrecognized event", where previously it would just be"unrecognized event".The constraint of
EMap["event" & Lowercase<T>]in turn is reduced toEMap["event" & Lowercase<string>].This is where things go wrong. We currently lack the ability to reduce unions and intersections of string literal types (like
"event") and string mapping types with non-generic placeholders (likeLowercase<string>). The intersection"event" & Lowercase<string>really should reduce to just"event", but it doesn’t. So, we fail to consider it a valid index type inEMap["event" & Lowercase<string>], which therefore ends up beingunknown. Andunknownisn’t assignable to{}, so therefore error.So, long story short, we can fix this issue by doing a better job reducing unions and intersections of string literal types and string mapping types with non-generic placeholders. I will look at putting up a PR.
Ok, I see the same effects with your repro. The root cause is #56004, but the issue only shows up after #56598 because that PR fixes template literal placeholder matching such that
`${string & Record<never, never>}`behaves the same as just`${string}`(which indeed it should). And apparently we use template literal matching when checking relations for two string mapping types (this happens inisMemberOfStringMapping). Crazy.Regarding the new react-hook-form error, the issue is the
Record<string, any>constraint onT. We have rule that says an object with an[x: string]: anyindex signature is a supertype of any object type, even if that object type doesn’t have a matching index signature. This includes function types, so in the example, thetypeof options === "function"check can’t just narrow the type toAsyncDefaultValues<T>. Indeed,optionscould be any arbitrary function. To wit, this call is permitted:The reason we issue an implicit any error on the
dataparameter is that, since the function check can really only narrow to typeFunction, we end up with an untyped function call.Things work fine when the constraint of
Tis changed toRecord<string, unknown>. In that case we error on calls tofwith arbitrary function types, and we narrow toAsyncDefaultValues<T>following the function check.Other than adding a type assertion, I’m not sure what the best fix is in the react-hook-form project since new errors pop up if I just change the constraint to
Record<string, unknown>. But, certainly, I think our is correct and points out a latent issue in the code.@MichaelMitchell-at fix at #57113
Copying over my comment from #56972
Minimal repro of a “cannot be used as an index type” error: