Have you ever heard about TypeScript types narrowing? Have you ever seen such an error in your TypeScript code:
Even tough, you really knew that the
name property exists on the
person object? How did you solve this problem? Did you cast the variable to the expected type?
If the answer to at least one of those questions is yes, you might read on. There are better ways of determining the type of local variable in TypeScript. What’s more, TS compiler does a lot of stuff for us by leveraging types narrowing. In this article, we are going to see how it works and how it can be useful ?
Table of Contents
TypeScript types narrowing – what is that?
First, we need to understand that TypeScript does a lot of stuff in order to ensure we work with the most specific type as possible. Basically, if the exact type of local variable can be determined, TS compiler tries to do that.
Imagine such a function:
In vanilla JS, such code would of course compile. But in our case, TypeScript sees a problem:
The compiler is right here. Our parameter is either
number, so the
length property may not be available if someone passes a
You might have already been in such situations. What did you do? Well, sometimes when the code is more complex, and you just know that the variable contains the requested property, it might be tempting to cast:
Of course, we will satisfy the compiler here. But does that make our code any more safe than the previous version? Not at all.
In our example, based on the code we have written, TypeScript is not able to determine the exact type of
variable. We can help it by using type guards. We will talk about them in details in a separate article. However, for now it’s enough to know that the language has some built-in type guards – one of them is typeof. Let’s use it in our function:
That’s cool, TS compiler doesn’t complain anymore. But how does it work? Our code is still accessing
variable.length directly, there’s no casting there.
Notice what your IDE tells you when you hover your mouse over the
variable in the first if branch after checking if the type is
and also what it tells you when hovering over
variable in the
Wow! The IDE magically knows what’s the exact type of our locally scoped variable! ?
This magic is called types narrowing. TypeScript compiler does many things to ensure that the type of local variable you work with is of the most specific type possible. It is based on the complex analysis of the source code, especially the code surrounding the place in which the local variable is used.
in keyword in types narrowing
Let’s take a look at this code now:
Let’s say we have a variable which may either be
In that place, TypeScript can’t say whether
Maybe you’ve used the
in keyword for determining types before. Types narrowing also works with
As you can see, TypeScript analyzed the flow, and it noticed that in the first
if block we check whether the
person object contains the
employees property. If it does, the compiler known it must be
Employee. Cool, isn’t it? ?
Narrowing and equality operator
Another interesting application of TypeScript types narrowing is using the equality operator:
Notice how TypeScript determines the type of variables based on the
=== operator. If both parameters are equal, they must be both
TypeScript types narrowing – summary
Narrowing in TypeScript is a very power feature of the language. I just showed you some simple examples, so you can grasp the idea and notice how much TS compiler does to ensure your type is the correct one.
If you’re interested, you can read much more about this in TypeScript docs. It’s however worth knowing how TypeScript compiler works and how you should properly check for types in your code. Remember that using
any or explicit casting should be your last resort ?