I'm trying to understand why TS isn't narrowing inst
to just Bar
in the example below:
class Foo {}
class Bar { prop = "baz" }
function fn2(inst: Foo | Bar) {
if (inst instanceof Foo) {
inst = new Bar()
}
inst.prop // prop does not exist on Foo | Bar
}
CodePudding user response:
Typescript is structural, not nominal. So the problem here is that an instance of Bar
is assignable to type Foo
, so the type guard doesn't actually narrow anything.
class Foo {}
class Bar { prop = "baz" }
const inst: Foo = new Bar() // fine
An object with one property conforms to the interface of an object with no properties, since all properties (all zero of them) are accounted for.
To make this work, you need to make the two classes have different interfaces.
class Foo { foo = 'foo' }
class Bar { bar = 'bar' }
declare let inst: Foo | Bar
if (inst instanceof Foo) inst = new Bar()
inst.bar // works
inst.foo // error
Or in your specific case:
class Foo { foo = 'foo' }
class Bar { bar = 'bar' }
function fn2(inst: Foo | Bar) {
if (inst instanceof Foo) {
inst = new Bar()
}
inst.bar
}