In this article I will show you how to write safer TypeScript code by leveraging a feature called strictNullChecks. It’s quite easy to miss because it’s turned off by default, but can help a lot to produce more robust code. I’ll also briefly introduce another lesser-known feature of the language called type guards.

Some Java full-stack developers (like me) always wanted to have statically typed JavaScript. I remember when starting a new project with GWT and being quite amazed by the possibility of using Java on both sides.

Nowadays, many new languages are trying to be a replacement of JavaScript. TypeScript is one of them. I got my first experience with TypeScript when trying early betas of Angular 2. I quite liked a concept of adding static types to JavaScript. However, I also see developers trying to keep the freedom of JavaScript. Fortunately, TypeScript gives developers flexibility to decide what way they want to go and how they want to mix static vs dynamic types.

To experiment with these tradeoffs, I decided to use TypeScript for a new React/Redux project. The application is a web SPA which is the front end for a typical SAAS. Users can register/login, adding credit cards, managing api keys, see billing information, etc. All the examples in this article will be from that project and have React+Redux context.

Problem overview

One of the pain points of JavaScript is nulls and undefined values. I won’t deep dive into the problem as it has been described and discussed many times. Suffice to say that any developer who has tried to access an object that was null or undefined will probably recognise these sorts of error message:

Uncaught ReferenceError: foo is not defined
Uncaught TypeError: window.foo is not a function

These errors happen at runtime when you’ve deployed your code already. Ideally, we want to prevent them when writing the code, not when we are running it. That’s what strictNullChecks compiler flag is for.

Ideally, if you read the TypeScript manual before coding, you’d know about this flag already. In my case I was learning TypeScript code-first and only learnt about it after the fact. So, my first suggestion would be this: don’t be me, RTFM first! The TypeScript handbook is really tiny and handy. You can finish it in 2-3 days.

Strict null checks

strictNullChecks protects you from referencing nulls or undefined values in code. It can be enabled by adding the –strictNullChecks flag as an option to the command-line compiler, or adding it to tsconfig.json file.

The TypeScript developers actually encourage us to turn this option on. From the handbook:

As a note: we encourage the use of –strictNullChecks when possible, but for the purposes of this handbook, we will assume it is turned off.

It’s a good idea to enable it when your project starts. Otherwise you can end up with hundreds of compiler errors when you finally turn it on. By the time I got around to it enabling it, it took me about 3 hours to fix all of the resultant errors.

Let’s have a look at an example that will fail during compilation when flag is on (it compiles fine when flag is off):

The compiler gives us an error because `ownProps` is an optional argument and could be undefined. So this is the point where compiler is telling us: “Dude, watch for undefined!”.

To fix the problem we can use an upcoming ECMAScript feature called object spread that is implemented in TypeScript 2.1:


If `ownProps` is undefined then it will be just ignored. The important point is that we are prevented from accessing an object that could be undefined. Alternately, we would explicitly check `ownProps` to be defined (in an if condition) without object spreading syntax.

The next example shows how strictNullChecks could help not only make code safer but also reduce some boilerplate:

The compiler is failing on line 17 because we are trying to use a `newState` variable, but it’s possibly was never assigned (ah, that sweet uninitialised identifier). So to fix the error we can assign `newState` to `state` from the passed in arguments, and remove the `if` condition entirely:

That said, in some cases you want to use null or undefined values. For instance:

So in this case, returning undefined is a valid behaviour of the function. However, the compiler generates an error. To work around it, we need to explicitly add undefined to the function declaration to let the compiler know that it’s a valid case:

Now, if we try to use the function without checking the result, we will get additional errors. For example:

So in this case we should check that the return value is defined:

NOTE: I found that using undefined instead of null is more convenient, because TypeScript uses undefined in place of optional interfaces fields and function arguments.

Type guards

Type guards are another TypeScript feature that allows us to check types and automatically resolve them.

Consider this simple function that converts bytes to megabytes:

We’d like that if `this.props.usedBytes` is undefined, then usedMb() will return undefined. However, our current implementation won’t work as expected if `this.props.usedBytes` is assigned a zero value, as we’ll get undefined as a returned value when what we actually want is zero. You’d have to rely on unit tests to pick something up like that, but what’d be nice is we could check that the type of the property is a number.

Fortunately, TypeScript provides nice functionality to do that. It’s called a type guard. In our case it’s just a simple function that looks like this:

By having a return signature of the form ” is “, we’re telling the compiler to consider our function to be a type guard.

Then we can rewrite our original usedMb() function to use our type guard:

That said, using ‘any’ as an argument type for a type guard function is actually not that common. Type guards are more powerful when you can declare a range of passing types. The compiler can then distinguish between those types during usage. Consider this example from the handbook:

As you can see compiler knows that pet is of type Bird when goes to else statement.

Conclusion

TypeScript provides a couple of handy mechanisms for making your code safer.

In particular, I have found the ‘–strictNullChecks’ option to be very useful. It’s highlighted actual problems with my code, without generate any noise. I would highly recommend that you turn it on if you haven’t already. Also, using it tends to make your code not only safer but also smaller and more elegant.

Type guards are also an interesting feature, although to be honest I have less real-world experience with them.

Using these features takes some of the pressure off of your unit test suite to cover all possible scenarios. This doesn’t mean they should replace unit tests. Instead, they can complement them, especially when performing large refactorings.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s