Working with TypeScript has been amazing. One of the most common things I’ve been finding my self checking was whether one variable is of a certain type. Let’s look at an example.

interface Mammal {
    name: string;
}

interface Horse extends Mammal {
    canRun: boolean;
}

type Animal = Mammal | Horse;

const animalThings = (animal: Animal) => {
    if (animal instanceof Horse) { // Error: 'Horse' only refers to a type, but is being used as a value here.
        console.log("Run ", animal.name);
    } else {
        console.log('I do not run but my name is ', animal.name);
    }
}

Here we can see that that TypeScript is telling is that 'Horse' only refers to a type, but is being used as a value here.. To better understand what is happening here we need to remind ourselves what TypeScript is really doing. It’s taking our code and it’s transpilling it down to JavaScript. While it does that it strips away all the non JavaScript things, like type, interface, colons in the functions, everything. As a result the Horse type we reference doesn’t exist in the final transplilled code. Therefore the error.

How can you go past that? There are two ways here.

The JavaScript way

interface Mammal {
    name: string;
}

interface Horse extends Mammal {
    canRun: boolean;
}

type Animal = Mammal | Horse;

const animalThings = (animal: Animal) => {
    if ('canRun' in animal) { // We are OK now
        console.log("Run ", animal.name);
    } else {
        console.log('I do not run but my name is ', animal.name);
    }
}

Note that here we are using the in keyword in order to check that our object contains the unique to the horse variable canRun. That way we verify it’s an instance of Horse.

The TypeScript way

interface Mammal {
    kind: 'Mammal'; // Note the setting of kind here
    name: string;
}

interface Horse extends Mammal {
    kind: 'Horse'; // And here.
    canRun: boolean;
}

type Animal = Mammal | Horse;

const animalThings = (animal: Animal) => {
    if (animal.kind === 'Horse') { // We are also OK now.
        console.log("Run ", animal.name);
    } else {
        console.log('I do not run but my name is ', animal.name);
    }
}

Things are interesting here. When we are adding the keyword kind in the declaration of the interface we are essentially introducing a tag in order to explicitly store the type of this interface. This is called a tagged union and it’s widely used.

Personally I prefer the Typescript solution when I work on a TypeScript project. It feels more in line with the TypeScript ethos and phillosophy.

More reading about tagged unions can be found here and here.