Overview
The release of TypeScript 2.0 shipped with plenty of new features. In this post, we’ll be looking at non-nullable types, a fundamental improvement to the type system that helps prevent an entire category of nullability errors at compile-time.
The null
and undefined
Values
|
|
Let’s take the number
type as an example. Its domain not only includes all IEEE 754 floating point numbers, but the two special values null
and undefined
as well:
The same was true for objects, array, and function types. There was no way to express via the type system that a specific variable was meant to be non-nullable. Luckily, TypeScript 2.0 fixes that problem.
Strict Null Checking
TypeScript 2.0 adds support for non-nullable types. There’s a new strict null checking mode that you can opt into by providing the --strictNullChecks
flag on the command line. Alternatively, you can enable the strictNullChecks
compiler option within your project’s tsconfig.json file:
|
|
In strict null checking mode, null
and undefined
are no longer assignable to every type. Both null
and undefined
now have their own types, each with only one value:
If we compile our previous examples with strict null checks enabled, attempting to assign null
or undefined
to any of the variables results in a type error:
|
|
So how do we make a variable nullable in TypeScript 2.0?
Modeling Nullability with Union Types
Since types are non-nullable by default when strict null checking is enabled, we need to explicitly opt into nullability and tell the type checker which variables we want to be nullable. We do this by constructing a union type containing the null
or undefined
types:
|
|
Note that undefined
is not a valid value for the name
variable since the union type doesn’t contain the undefined
type.
A big advantage of this nullability approach is that it becomes evident and self-documenting which members of a type are nullable. Take this simple User
type as an example:
|
|
We can make the lastName
property optional by appending a ?
to its name, which allows us to omit the definition of the lastName
property entirely. In addition, the undefined
type is automatically added to the union type. Therefore, all of the following assignments are type-correct:
|
|
Property Access with Nullable Types
If an object is of a type that includes null
or undefined
, accessing any property produces a compile-time error:
|
|
Before accessing a property, you need to use a type guard to check whether the property access on the given object is safe:
|
|
TypeScript understands JavaScript’s truthiness semantics and supports type guards in conditional expressions, so this approach works fine as well:
|
|
Function Invocations with Nullable Types
If you attempt to call a function that is of a type that includes null
or undefined
, a compile-time error is produced. The callback
parameter below is optional (note the ?
), so it could possibly be undefined
. Therefore, it cannot be called directly:
|
|
Similar to checking objects before accessing a property, we need to check first whether the function has a non-null value:
|
|
You can also check the value returned by the typeof
operator, if you prefer:
|
|
Summary
Non-nullable types are a fundamental and valuable addition to TypeScript’s type system. They allow for precise modeling of which variables and properties are nullable. A property access or function call is only allowed after a type guard has determined it to be safe, thus preventing many nullability errors at compile-time.