dsifford dsifford -4 years ago 153
TypeScript Question

Union Type: One or the other failing. Not sure if this is by design or a bug

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!

Answer Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download