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
Bug: Control flow type analysis regression. #11153
This code compiles in TS 1.8 but not in 2.0.3 Code
classA{}classB{constructor(publicb: number){}}functionfoo(x: A|B): number|boolean{if(xinstanceofA){returntrue;}elseif(xinstanceofB){returnx.b;}// ^ Property 'b' does not exist on type 'never'.};
This error only appears if class A has no fields or methods,
if I add a field or a method the error disappears (but not constructor).
This is working as intended. The problem here is that structurallyA and B are the same type (because constructors don't affect the instance type). So, the x instanceof A check also eliminates B. As you mention, it will behave correctly as long as there is some structural difference between A and B, so that is the workaround.
That said, this is not the first time someone has reported this issue. In the particular case of instanceof it would be nice to somehow treat A and Bnominally as that would more accurately reflect what happens a run-time.
Sorry, I missed the public modifier in the constructor in your first example. You're right, A and B are not structurally identical. Rather, B is a subtype of A.
There are more details on the changes since 1.8 in #10194 and #10216. The core issue we have is that we use structural subtype relationships to reason about instanceof which isn't always correct. Specifically, it produces different results in cases where classes that don't extend each other are structurally identical or structural subtypes. We've been discussing ways to fix this but haven't yet done so.
Activity
ahejlsberg commentedon Sep 26, 2016
This is working as intended. The problem here is that structurally
AandBare the same type (because constructors don't affect the instance type). So, thex instanceof Acheck also eliminatesB. As you mention, it will behave correctly as long as there is some structural difference betweenAandB, so that is the workaround.That said, this is not the first time someone has reported this issue. In the particular case of
instanceofit would be nice to somehow treatAandBnominally as that would more accurately reflect what happens a run-time.vagarenko commentedon Sep 26, 2016
Anders Hejlsberg (@ahejlsberg)
I don't understand. How can they be structually identical if type
Bhas fieldb: numberand typeAhas none?Why then this code compiles fine:
?
There is no structual difference between
AandBhere.Also, as I said this worked fine in Typescript 1.8 and it isn't mentioned in Breaking Changes page.
ahejlsberg commentedon Sep 28, 2016
Sorry, I missed the
publicmodifier in the constructor in your first example. You're right,AandBare not structurally identical. Rather,Bis a subtype ofA.There are more details on the changes since 1.8 in #10194 and #10216. The core issue we have is that we use structural subtype relationships to reason about
instanceofwhich isn't always correct. Specifically, it produces different results in cases where classes that don't extend each other are structurally identical or structural subtypes. We've been discussing ways to fix this but haven't yet done so.