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
{{ message }}
Repository navigation
Regression in nightly build related to keyof, type narrowing, and exactOptionalPropertyTypes #55756
I'm like 99% positive this has come up before in different contexts but basically, yeah, the compiler only sees the types in zero-order and doesn't understand the higher-order concept that p necessarily refers to the same property in both positions. Supporting that would likely require #30581 or something similar.
we should narrow down which PR did this
Ryan Cavanaugh (@RyanCavanaugh) Looks like that'd be #55585, if typescript-bot's updated bisect is correct (the commit you quoted is different from the one that's linked now).
I can't say this one was intended but it also looks to me like a correctness improvement. What I can offer is to add some tests covering this but other than that LGTM and the issue could be closed.
which should be an error (and also changed at the same time).
I can't say this one was intended but it also looks to me like a correctness improvement.
Adding an explicit | undefined to eitherpropertyA's -OR- propertyB's declaration makes this new error disappear. Seems like this new checking/error is incomplete (i.e., still possible to get undefinedexplicitly stored in a signature that doesn't have | undefined in its declaration).
Adding an explicit | undefined to eitherpropertyA's -OR- propertyB's declaration makes this new error disappear. Seems like this new checking/error is incomplete (i.e., still possible to get undefinedexplicitly stored in a signature that doesn't have | undefined in its declaration).
SlurpTheo I’d recommend opening a new issue for that because it definitely sounds like a bug.
I can't come up with a reproduction that doesn't involve { _brand: any }; and with any involved, I don't feel like quibbling over ~inconsistencies.
Yeah, that's expected; once you have an any involved all bets are off because both any | Tandany & T just reduce to any. To be specific, what the assignability check for dest[p] = src[p] asks is: "Is the union of all properties potentially selected by p assignable to the intersection of those properties?" So that behavior for any is actually consistent, despite outward appearances.
#30769 was a similar change made years ago that was likewise a big source of consternation when first introduced, for what it's worth.
Whoa 👀
(~fn3() example in the main text of that issue)
typeT=Record<string,unknown>;functionf3<UextendsT>(p: {objT: T;objU: U}){p.objT["foo"]=11;// !!! I'm not sure I understand !!!// @ts-expect-error ts(2536): Type '"foo"' cannot be used to index type 'U'.p.objU["foo"]=22;// @ts-expect-error ts(2352): Property 'foo' is missing in type 'T' but required in type '{ foo: unknown; }'.(p.objUas{foo: unknown})["foo"]=222;(p.objUas{foo?: unknown})["foo"]=2222;(p.objUasT)["foo"]=22222;}f3({objT: {},objU: {}});f3<{bar: unknown}>({objT: {baz: 33},objU: {bar: 44},});f3<{bar: unknown}>({objT: {baz: 33},objU: {bar: 44,// @ts-expect-error ts(2322): Object literal may only specify known properties, and 'qux' does not exist in type '{ bar: unknown; }'.qux: 55,},});constobjU1={bar: 44,qux: 55,};f3<{bar: unknown}>({objT: {baz: 33},objU: objU1,});constobjU2={qux: 55,};f3<{bar: unknown}>({objT: {baz: 33},// @ts-expect-error ts(2741): Property 'bar' is missing in type '{ qux: number; }' but required in type '{ bar: unknown; }'.objU: objU2,});
Setting properties on U is different than setting properties on T even though U extends T?
Setting properties on U is different than setting properties on T even though U extends T?
I mean that pull request does state the following:
Given a type variable T with a constraint C, when an indexed access T[K] occurs on the target side of a type relationship, index signatures in C are now ignored. This is because a type argument for T isn't actually required to have an index signature, it is just required to have properties with matching types.
Activity
typescript-bot commentedon Sep 15, 2023
The change between origin/release-5.2 and origin/main occurred at e6321d7.
RyanCavanaugh commentedon Sep 15, 2023
Uh, no
RyanCavanaugh commentedon Sep 15, 2023
This seems like a correct change. The example is not, from TypeScript's perspective, any different from
which should be an error (and also changed at the same time).
That said, we should narrow down which PR did this to make sure it was at least somewhat intended.
fatcerberus commentedon Sep 16, 2023
I'm like 99% positive this has come up before in different contexts but basically, yeah, the compiler only sees the types in zero-order and doesn't understand the higher-order concept that
pnecessarily refers to the same property in both positions. Supporting that would likely require #30581 or something similar.Ryan Cavanaugh (@RyanCavanaugh) Looks like that'd be #55585, if typescript-bot's updated bisect is correct (the commit you quoted is different from the one that's linked now).
jakebailey commentedon Sep 16, 2023
A local bisect confirms that this is due to #55585. Mateusz Burzyński (@Andarist)
Andarist commentedon Sep 16, 2023
I can't say this one was intended but it also looks to me like a correctness improvement. What I can offer is to add some tests covering this but other than that LGTM and the issue could be closed.
SlurpTheo commentedon Sep 18, 2023
Adding an explicit
| undefinedto eitherpropertyA's -OR-propertyB's declaration makes this new error disappear. Seems like this new checking/error is incomplete (i.e., still possible to getundefinedexplicitly stored in a signature that doesn't have| undefinedin its declaration).fatcerberus commentedon Sep 18, 2023
SlurpTheo I’d recommend opening a new issue for that because it definitely sounds like a bug.
SlurpTheo commentedon Sep 19, 2023
I can't come up with a reproduction that doesn't involve
{ _brand: any }; and withanyinvolved, I don't feel like quibbling over ~inconsistencies.Playground link
fatcerberus commentedon Sep 19, 2023
Yeah, that's expected; once you have an
anyinvolved all bets are off because bothany | Tandany & Tjust reduce toany. To be specific, what the assignability check fordest[p] = src[p]asks is: "Is the union of all properties potentially selected bypassignable to the intersection of those properties?" So that behavior foranyis actually consistent, despite outward appearances.fatcerberus commentedon Sep 19, 2023
#30769 was a similar change made years ago that was likewise a big source of consternation when first introduced, for what it's worth.
typescript-bot commentedon Sep 22, 2023
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
SlurpTheo commentedon Oct 6, 2023
Whoa 👀
(~
fn3()example in the main text of that issue)Setting properties on
Uis different than setting properties onTeven thoughU extends T?Playground
SlurpTheo commentedon Oct 6, 2023
I mean that pull request does state the following:
But it still makes me 😵