Open SoraKumo001 opened 3 years ago
I was able to temporarily work around the problem by inserting 'extends' once! This code also works in 4.3.2 and previous versions.
type Base = { 100: { a: number }; 200: { b: string } }
type NewType<T = Base> = {
[P in keyof T ]:(({
code: P
body: T[P]
}) )
} extends {
//[P in keyof T ]: infer R
[P in keyof T ]: unknown extends unknown ? infer R : never
}
? R
: never
let test: NewType
Another workaround (tried on ts 4.4.0-dev.20210530):
type NewType<T> = {
[P in keyof T]: {
code: P
body: T[P]
}
}[keyof T]
type Base = { 100: { a: number }; 200: { b: string } }
declare const test: NewType<Base>
Looks like this was broken by #43649.
@weswigham I'm not sure about the changes in #43649. They break the example in this issue because, as we check that inferences for R
are assignable to the constraint of R
(which is computed by #43649), the constraint contains un-instantiated references to T
and the assignability check therefore fails. When then pick the constraint instead, which subsequently is instantiated with the type passed for T
. But that's too late and not the result we want. We could potentially consider adding logic to somehow instantiate the constraint before the assignability check, but that would further complicate the inference process in conditional types and I'm not even sure I agree it's the right thing to do. I think it is perfectly fine for the inferred R
to not have a constraint--and, honestly, there are many similar situations in which we don't produce constraints (e.g. if the check type is just a regular object type).
My recommendation would be to back out #43649. That of course means #43357, the issue it fixes, needs some other solution. As you yourself point out, it never really should have worked, and I think the right solution is to explicitly intersect with keyof T
in the KeysWithoutStringIndex<T>
type, i.e.
type KeysWithoutStringIndex<T> =
({ [K in keyof T]: string extends K ? never : K } extends { [_ in keyof T]: infer U } ? U : never) & keyof T;
I think our syntactic inference constraint rules are kiiiiiinda arbitrary to begin with (what type parameters we match up across what locations has kinda been chosen by request) - I "fixed" the issue by adding one because the change in behavior was technically a regression, and adding those syntactic constraints is sort-of free to do. The extra instantiation would probably be the best thing we could do to keep the old behavior going. We could back it out... But then we'd be reintroducing the old regression...
Bug Report
The conversion result of 'Mapped Types' has changed in 4.3.2 or later typescript.
💻 Code
🙁 Actual behavior
🙂 Expected behavior
Hoping to return to pre-4.3.0-beta behavior!