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
Union of a nullable and not nullable setter results wrongly into a nullable setterย #50142
classNullable{publicsetfoo(_newValue : number|null){}}classNotNullable{publicsetfoo(_newValue : number){}}constnullable=newNullable();constnotNullable=newNotNullable();// correctly, we cannot assign "null" to "notNullable"nullable.foo=null;notNullable.foo=null;// This is correctly a compile error.// When using a union of both types I would assume that you still cannot assign "null" because// the union has to fullfill the constrains of both types. But, here you can assign "null".functionserviceMethod(a : Nullable|NotNullable) : void{a.foo=null;// This is not a compile error, but I think it should be.}
๐ Actual behavior
When using a union of two types with a setter where one is nullable and another one is not, the resulting setter is also nullable.
๐ Expected behavior
I believe this is wrong, as the union must ensure that the constraints of both types are fulfilled. Which mean that null should be prohibited as one of the types does not allow it.
Properties are always measured covariantly, and this is unsound under supertype aliasing.
I am not sure if I understand this completely. If this is unsound, I cannot follow why it should be the expected behavior. If there is somewhere a more detailed reading about the reasoning, I would be glad to get a pointing.
For the same reason that { foo: number } is assignable to { foo: number | undefined } and Cat[] is assignable to Animal[]: it's unsound, but a ton of real-world code would be broken if it weren't allowed. The unsoundness in your case is a consequence of subtype reduction: Nullable | NonNullable is treated as a Nullable because the former is considered a supertype of the latter.
Activity
MartinJohns commentedon Aug 2, 2022
Related: #45376
RyanCavanaugh commentedon Aug 2, 2022
Properties are always measured covariantly, and this is unsound under supertype aliasing.
fatcerberus commentedon Aug 2, 2022
I'm kind of surprised this isn't caught under the rules of #30769. Even
a['foo'] = nullis accepted. Probably subtype reduction kicking in.MiladSadinam commentedon Aug 2, 2022
I am not sure if I understand this completely. If this is unsound, I cannot follow why it should be the expected behavior. If there is somewhere a more detailed reading about the reasoning, I would be glad to get a pointing.
fatcerberus commentedon Aug 2, 2022
For the same reason that
{ foo: number }is assignable to{ foo: number | undefined }andCat[]is assignable toAnimal[]: it's unsound, but a ton of real-world code would be broken if it weren't allowed. The unsoundness in your case is a consequence of subtype reduction:Nullable | NonNullableis treated as aNullablebecause the former is considered a supertype of the latter.MiladSadinam commentedon Aug 2, 2022
Thank you for the explanation. I can follow the reasoning.
Though, concerning the backwards compatibility: Typescript has introduced many optional "strict" flags to solve this problem.
Jamesernator commentedon Aug 4, 2022
N
typescript-bot commentedon Aug 6, 2022
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.