Consider a situation where an object can have exactly the FooBar
or Baz
interface listed below.
interface FooBar {
foo: string;
bar: string;
}
interface Baz {
baz: string;
}
It's my understanding that this "one or the other" situation can be handled by creating a union between FooBar
and Baz
.
type FooBarOrBaz = FooBar | Baz;
So far so good...
The issue I'm having is that the following object passes type checking:
const x: FooBarOrBaz = {
foo: 'foo',
baz: 'foo',
};
Is this a bug?
Playground Example
Thanks in advance!
I think there is a bug here.
It can be made even more explicit by switching to classes and then using the type narrowing aspects of instanceof
on union types.
Start with your code, but switched to classes:
class FooBar {
foo: string;
bar: string;
}
class Baz {
baz: string;
}
type FooBarOrBaz = FooBar | Baz;
Create an instance, as you did - compiles fine.
const x: FooBarOrBaz = {
foo: 'foo',
baz: 'baz',
}
Check if we've got a FooBar
:
if (x instanceof FooBar) {
console.log("x is a FooBar : (" + x.foo + "," + x.bar + ")");
} else {
console.log("x is not FooBar must be Baz : " + x.baz);
}
This compiles without warnings and prints x is not FooBar must be Baz : baz
.
Check if we've got a Baz
:
if (x instanceof Baz) {
console.log("x is a Baz : (" + x.baz + ")");
} else {
console.log("x is not Baz must be FooBar : " + x.foo + "," + x.bar);
}
Also compiles fine, but prints x is not Baz must be FooBar : foo,undefined
So either accepting this kind of input is a bug, or allowing it leads to a bug in the type narrowing of the instanceof
type guard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With