
Today I’m going to share one of my favourite TypeScript patterns: type guards.
Generic Type Guards are pretty handy for narrowing types!#TypeScript #webdevelopment pic.twitter.com/tiOeHIOgYc
— Harry Nicholls (@HarryNicholls) February 27, 2019
Do you regularly work with TypeScript?
You might’ve run into an error similar to this:

If you know that vehicle
does have the property turnSteeringWheel
, you can quickly solve this issue by casting vehicle
as any.
But you could be wrong!
What if the app changes and future-you forgets what you did?! We’ve all been there…
When using any
, you’re overriding the compiler and losing the type-safety that TypeScript affords you.
Yes, the compiler is happy. Yes your code runs, and your tests pass.
Hooray 🎉
But don’t celebrate just yet. It’s a fragile approach and you’re inviting errors to the party.
If there’s a child of this component that doesn’t have props
, you’ll get a runtime error.
Thankfully, using any
is not the only solution.
Let me propose a solution that un-invites runtime errors to your type-safe party.
A type-safe solution
TypeScript allows you to create something called a type guard.
The TypeScript Handbook describes type guards as:
Some expression that performs a runtime check that guarantees the type in some scope.
The key here is “a runtime check”. This ensures that the variable is the type you’re expecting at the moment your code is executed.
That’s great, but will it satisfy the compiler too?
Yes it will!
Another key characteristic of a type guard is that it must return a type predicate.
A type predicate being something along the lines of vehicle is Car
or event is MouseEvent
.
When a function returns this, it tells the compiler that the type of the thing passed in will be narrowed. That is, the type will become more specific.
vehicle is Car
tells the compiler that we’ve now confirmed that the vehicle
passed in to the type guard is in fact a Car
.
Say for example, you have a system like this:
Even though you know vehicle
is a Car
, VehicleController
has stripped it down to a basic Vehicle
.
And that’s how the TypeScript compiler interprets it.
Because Vehicle
doesn’t have the property turnSteeringWheel
, you can’t compile this code because the TS compiler thinks you’ve made a mistake.
Type guards can help you bridge this gap. A simple one looks like this:
This casts vehicle
as a Car
, and checks if it has a turnSteeringWheel
method.
The compiler still considers vehicle
to be a Vehicle
, so you have to cast it as a Car
for a second time, but at least you can be confident that turnSteeringWheel
is defined.
The downside is this pattern isn’t very reusable, you’d have to write the same block of code every time you want to use it.
Built-in type guards
TypeScript comes with some built-in type guards: typeof
and instanceof
.
They’re very useful, but have limited scope.
For example, typeof
can only be used to check string
, number
, bigint
, function
, boolean
, symbol
, object
, and undefined
types.
You might be thinking, “What other types are there?”
The catch is that typeof
only performs a shallow type-check.
It can determine if a variable is a generic object, but cannot tell you the shape of the object.
So typeof
is best used for simple types, or, as I most often use it, to check for undefined
variables:
Having said this, you could also do away with typeof
here by using a ternary: const combinedClassNames = optionalProp ? `${className} optionalClass` : className;
.
The second built-in type guard, instanceof
, is a bit more interesting.
You can use it to check if a variable is an instance of a given class.
I wonder what’ll happen if we apply that to the Vehicle
and Car
problem from above?
Cool! No more TS errors, and the syntax is a lot less verbose than the casting method.
There’s just one catch here: instanceof
only works for classes…
So this doesn’t work:
Even though anotherCar
has the same shape as a Car
, it’s not an instance of the class, so in this case vehicle instanceof Car
returns false
.
Both typeof
and instanceof
are useful, but have limited scope in modern, functional programming.
So how can you check the type of any object?
Luckily, you can create custom type guards.
Custom type guards
If you’re into functional programming, you’ll be more accustomed to NOT using classes, so I haven’t really helped you solve any problems yet.
You can still use type guards, you just need to create your own.
Let’s continue to use the vehicle and car example, like so:
You can pass anything into this function, and check if it’s a Car
.
One of the most important features of this function is the return type, variableToCheck is Car
.
As mentioned above, this is a “type predicate”.
We’re not just checking if the variable has a turnSteeringWheel
property, we’re telling the TS compiler if the logical statement returns true
, then this variable is a Car
.
So now we can refactor this:
To this:
Cool, eh?

You can apply this pattern to any type you can dream up.
What goes into a custom type guard?
The key features of a custom type guard are:
- Returns a type predicate, e.g.
variableToCheck is Car
- Contains a logical statement that can accurately determine the type of the given variable, e.g
(variableToCheck as Car).turnSteeringWheel !== undefined
Some other examples include:
If you have a lot of types to check though, it could become quite tedious to create and maintain a unique type guard for each type.
That’s where another awesome TypeScript feature comes in: generics.
A generic type guard
If you’re not familiar with generics, check out the TypeScript Handbook generics section.
You might’ve noticed that there’s a common pattern, and a lot of repitition, between the custom type guards above.
They’re not very DRY. This is where generics come in handy.
Here’s a generic type guard, that you can use to narrow types whenever you need to.
You can use it like so:
Now you don’t have to write unique type guard functions for every single type you want to check.
Just plug your desired type and unique property into isOfType
.
You’ll satisfy the compiler, while being confident that you have type-safety at runtime.
Everybody wins!
A caveat

The type guards I’ve shown so far are fairly naïve.
In the Car
example, we’re assuming that turnSteeringWheel
is unique to Car
s.
The type guard asserts that if turnSteeringWheel
exists on the given variable, then it’s a Car
.
But this might not be true.
You could also have a Bus
type:
In this scenario, there isn’t a problem with the Bus
being cast as a Car
, because we’re only calling turnSteeringWheel
which happens to exist on both types.
However this might be a problem for you in more complex scenarios, so use type guards responsibly.
Recap
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 (Vehicle
versus the more specific Car
).
There are built-in type guards that you can use (typeof
and instanceof
) but they have limited use in functional programming.
If you need more flexible type guards you can define your own with a type predicate (vehicle is Car
), and a “unique” property of the type you want.
Or you can use the generic isOfType
util I outlined above.
Just remember that custom type guards can be a little naïve in complex apps.
Tl;dr: type guards rock 🤘.