What are type Guards in Typescript

avatar

Borislav Hadzhiev

Sat Feb 20 20213 min read

banner

Photo by Ryan Stone

Type Guards theory #

We use type guards in typescript when we have logic that is specific to a particular type.

In other words:

if (typeof someValue === 'string') { // someValue is guaranteed to be of type string // => therefore we can perform all string operations with it // like call someValue.toLowerCase(), etc. }

We want to force typescript to allow us to work with a value as if it's guaranteed to be of type "x". Once we run a type guard, we clarify to typescript the type of value we are working with.

Type Guards example #

function sum(a: string | number, b: string | number): string | number { // a and b are either of type string or number // therefore we can only use methods on them, // that are common between strings and numbers // i.e. .toString() and .valueOf() if (typeof a === 'string' && typeof b === 'string') { // both a and b are guaranteed to be of type string // can call all string methods on them return a.toUpperCase() + b.toUpperCase(); } if (typeof a === 'number' && typeof b === 'number') { // both a and b are guaranteed to be of type number // can call all number methods on them return a.toFixed(2) + b.toFixed(2); } if (typeof a === 'string' || typeof b === 'string') { // we don't know if a or b is the string, // so we don't get to call string methods on either one of them return String(a) + String(b); } // we have exhausted all the possibilities // Now a and b are guaranteed to be of type 'number' return a.toFixed(2) + b.toFixed(2); }

We often use type guards when working with union types, if we have an either or scenario and we have to narrow down the type of value we're working with to make sure the operations we're trying to perform will be type safe.

Checking primitives vs checking objects #

In the above example we used typeof to narrow down the type and use a type guard, we only use typeof with primitive values:

  • if (typeof someNumber === 'number') {guaranteed to be a number}
  • if (typeof someString === 'string') {guaranteed to be a string}
  • if (typeof someBoolean === 'boolean') {guaranteed to be of type boolean}

For non primitive types we use instanceof:

  • if (someObject instanceof someClass) {guaranteed to be of type someClass}
function loop(collection: string[] | string): void { // can only access common methods to both // string[] and string if (Array.isArray(collection)) { // collection is guaranteed to be a string[] collection.push('hello world'); } // The above is the same as if (collection instanceof Array) { // collection is guaranteed to be a string[] collection.push('hello world'); } if (typeof collection === 'string') { // collection is guaranteed to be a string console.log(collection.toUpperCase()); } }

Even though typeof would work with an object, it does not work as a type guard in typescript. For example typeof an array in javascript would return "object", but it does not function as a type guard in typescript.

We use type guards anytime we want to narrow down the type of a union type and restore a set of type specific properties on the value.

Add me on LinkedIn

I'm a Web Developer with TypeScript, React.js, Node.js and AWS experience.

Let's connect on LinkedIn

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee