Matej
Space of Matej

Space of Matej

How to use Type guards in Typescript

How to use Type guards in Typescript

A tutorial on how to correctly differentiate between types in Typescript

Matej's photo
Matej

Published on Sep 7, 2021

3 min read

Union types can be quite useful when multiple types have overlapping properties; for example, Animals all have names, but some animals bark, some meow, some moo, etc...

But how can we find the difference between the types?

At some point, it becomes important when we want an animal to raise its sound to know if it has to bark, moo or meow, so how do we do that in typescript?

Let's set an example:

type Cat = {
  name: string;
  meow: () => void;
}

type Dog = {
  name: string;
  bark: () => void;
};

type Cow = {
  name: string;
  moo: () => void;
};

We have 3 types here: Cat, Dog and Cow. They all share the name property, but what makes them unique is their capabilities of giving sound; this is the bark property for Dogs, meow for cats, and moo-ing for the cow.

Let's initialize our animals:

const rex: Dog = {
  name: 'Rex',
  bark: () => {
    console.log('🐶 Woof 🐶');
  }
};

const mrBubbles: Cat = {
  name: 'Mr. Bubbles',
  meow: () => {
    console.log('🐈 MEOW 🐈')
  }
};

const helga: Cow = {
  name: 'Helga',
  moo: () => {
    console.log('🐮 Moo 🐮')
  }
};

We've given them names and unique voices (since every dog bark sounds different).

Making a difference by the animal sound

So we create a function called makeSound which makes the animal well... sound:

const makeSound = (animal: Dog | Cat | Cow) => { }

Now, if we want to distinguish which animal is making a sound, we need functions to tell which animal it is:

const isCat = (animal: Dog | Cat | Cow): animal is Cat => {
  return (animal as Cat).meow !== undefined;
}

const isDog = (animal: Dog | Cat | Cow): animal is Cow => {
  return (animal as Dog).bark !== undefined;
}

const isCow = (animal: Dog | Cat | Cow): animal is Cow => {
  return (animal as Cow).moo !== undefined;
}

The return statement of animal is Cat, for example, expects a boolean value. This value tells typescript if this animal is a Cat. The meow property makes an animal a Cat, so that's why we check if that is not undefined.

Let's make them give their sound

To use this, we have to call it with our variable, and typescript knows which type we're operating with:

const makeSound = (animal: Dog | Cat | Cow) => {
  if (isCat(animal)) {
    animal.meow();
  } else if (isCow(animal)) {
    animal.moo();
  } else {
    animal.bark();
  }
}

makeSound(rex); // => 🐶 Woof 🐶
makeSound(helga); // => 🐮 Moo 🐮
makeSound(mrBubbles); // =>🐈 Meow 🐈

Other types of usages

Usually, we would see animals in some array like this:

const animals = [rex, mrBubbles, helga];

But now we have to make only the dogs bark, how do we do that? Well, we can filter out only the dogs with our method.

const onlyDogs: Dog[] = animals.filter((animal) => isDog(animal));

Conclusion

I hope this short tutorial helped you explain how to differentiate between types in Typescript.

If you like what I'm writing, leave a comment and let me know if it was helpful!

Thanks for reading! 👋

 
Share this