How to check the type of an object in TypeScript: type guards

How to check the type of an object in TypeScript: type guards

Created
Feb 13, 2022
Description
Type checking in TypeScript
Tags
TypeScript
WebDev
Public
A common pattern that I’ve repeated as a prior JS developer for checking the type of an object is something like:
if (obj.property) {
  // obj.property exists!
}
 
Sadly, this is not possible in TypeScript.

The problem

This is kind of classic in TypeScript: an object type that we would like to differentiate for different cases. In the following example we have two types, Fish and Bird:
type Fish = {
  name: string,
  swim: () => void
}

type Bird = {
  name: string,
  fly: () => void
}

type Pet = Fish | Bird
 
We can easily print the name of the Pet, but if we want to use the methods swim and fly, it becomes more complicated.
const printFishOrBird = (pet: Pet) => {
  // Error TS2339: Property 'swim' doesn't exist on type 'Pet'
  if (pet.swim) {
    console.log('Fish')
  } else {
    console.log('Bird')
  }
}
The example above doesn’t work because swim is not defined.
 

The solution: Type guards

Type guards are incredibly useful for narrowing types, satisfying the TS compiler, and helping to ensure runtime type-safety.
The most common scenario in which you’d want to use one is when a type you’re given isn’t as specific as you’d like (Pet vs a more specific Fish).
 
As we can see in the TypeScript docs, for the example above, we simply need to define a function whose return type is a type predicate:
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}
The key here is the return type: pet is Fish. TypeScript understands that if we return true, the argument is Fish, and we can use this variable.

Caveat

The type guards used in the previous example are fairly naive.
In the Fish example, we’re assuming that swim is unique to Fish.
The type guard asserts that if swim exists on the given variable, then it’s a Fish. But this might not be true.
We could also have a Dolphin type and the assert would not be precise in all the cases.
This might be a problem in more complex scenarios, so use type guards responsibly.
 

Loading Comments...