TypeScript: Keeping Type Guards Safe and Up To Date

Generic type guards help us write better code with fewer bugs

I enjoy TypeScript and find the type safety to be a huge benefit to my code. However, Type Guards have been a feature that I was not completely certain of. A Type Guard allows you to check the type of a variable before performing an action. In plain JavaScript, it would look like the following

let pet = getSmallPet();

// Each of these property accesses will cause an error

if (pet.swim) {

pet.swim();

} else if (pet.fly) {

pet.fly();

}

Set up: Configure our global TS

In this example, we will work with the following global augmentation, which is the only downside in this story.

If you do not want to use the global augmentation, check out the library mentioned at the end of this article.

From here on, we will learn how to create safe Type Guards.

Creating Type Guards

Let’s say, we have the following interface.

An unsafe Type Guard for this interface may look like this.

This works fine unless we add a new property something to our interface.

We need to keep in our mind to update the isPerson function. TypeScript will not warn us about the new property not being checked. If we don’t update our isPerson function, the code may be unstable, as the function does not even check the existence of property something .

Thankfully, there is a way to make Type Guards safe and aware of any change.

Instead of writing typical unsafe Type Guards, we could write parsers.

This function is statically typed and whenever we change the interface of Person , the TypeScript will warn us about the change and we will have to update our parsePerson function.

This works great, but it will get really annoying after a few days. Neeing to always create a new variable and check for null gets exhausting.

We could use something like this!

It is a simple function, which takes some data and a parser. We apply the parser on our data and if the result is not null, the data is in the correct format.

In our code, we could use the checkType function this way.

This looks much better! But…

Writing always checkType(data, parsePerson) is not exactly the way we want to validate our data structures.

We want to use the function like this isPerson(data) , right?

Correct Solution

Here is the long-awaited way to create elegant Type Guards.

A function which takes a parser and returns the safe Type Guard

And then we can use.

Hurrayyy!

createTypeGuard takes a parser and returns a type-safe Type Guard, which means, whenever we change the Person interface, we will be warned by TypeScript. Check it on the playground http://bit.ly/ts-safe-typeguard

Code Recapitulation

Conclusion

Write Type Guards as little as possible and if you write them, write them generic.

Unsafe Type Guards could be a new any to your code and could make your application unstable.

I have created a small library you can use to create safe Type Guards in your project. There is also no need to do the global augmentation if you decide to use this library. Check it here https://www.npmjs.com/package/create-typeguard

If you do not want to miss any new articles from my side, you can follow me on my Twitter https://twitter.com/michalszorad