TypeScript Types Deep Dive - Part 2: The Absence of value
Tags: typescript, javascript, webdev
Published: 2019-12-23 15:03:26

---
title: TypeScript Types Deep Dive - Part 2: The Absence of value
published: true
description: An epic journey of discovery into the mysterious world of TypeScript's type system. Part 2 discuss how TypeScript models the absence of value and how it helps live in a world with null and undefined.
tags: [typescript,javascript,webdev]
canonical_url: https://www.barbarianmeetscoding.com/blog/2019/12/21/typescript-types-deep-dive-part-ii
cover_image: https://www.barbarianmeetscoding.com/images/typescript-types-deep-dive.jpg
series: TypeScript Types Deep Dive
---

*This article was originally published on [Barbarian Meets Coding](https://www.barbarianmeetscoding.com/blog/2019/12/21/typescript-types-deep-dive-part-ii).*

TypeScript is a modern and safer version of JavaScript that has taken the web development world by storm. It is a superset of JavaScript that adds in some additional features, syntactic sugar and static type analysis aimed at making you more productive and able to scale your JavaScript projects. This is the **second part** of a series of articles where we explore TypeScript's comprehensive type system and learn how you can take advantage of it to **build very robust and maintainable web apps**.

> Haven't read the first part of this series? If you haven't you may want to <a href="/blog/2019/12/07/typescript-types-deep-dive-part-i">take a look</a>. There's lots of interesting and useful stuff in there.

## JavaScript and the absence of value

`null` is often referred to as **The Billion Dollar Mistake**. In the words of [Tony Hoare](https://en.wikipedia.org/wiki/Tony_Hoare) who first introduced it in ALGOL in 1965:

> I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to **ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler**. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
>
> <cite>Tony Hoare and [The Billion Dollar Mistake](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/)</cite>

Let's illustrate this pain with a simple example (although I'm pretty sure that you're likely familiar with it and have experienced it many times). 

Imagine we have such a function that allows us to destroy our evil enemies:

```javascript
// Destroy Thy Enemies!!
function attack(target) {
  target.hp -= 10;
}
```

Hmm... **It's Christmas. The time of joy, happiness and love.** So let's switch the example for something more suitable:

```javascript
// Love!!!!!
function hug(target) {
  target.happiness += 1000;
}
```

Now **THAT** is much better! So imagine that we want to take advantage of the `hug` function to spread some love around the world:

```javascript
// Love!!!!!
function hug(target) {
  target.happiness += 1000;
}

const sadJaime = {name: 'jaime', happiness: 0};
hug(sadJaime); // => Wihooo! ❤️
```

Great. Everything is going according to plan. We've made one person happier. Yippi! But what if we make our sample a little more convoluted? 

Let's say that we want to go ahead and hug everyone. Like EVERYONE in the world. We have this magic Map that has been pre-populated (probably by Santa) with every single human being alive on the planet right now. So we verify that it does indeed work as marketed:

```javascript
// Love!!!!!
function hug(target) {
  target.happiness += 1000;
}

const sadJaime = magicMap.get("Jaime"); // that's me of course
hug(sadJaime); // => Wihooo! ❤️
```

Excellent! But what if the person we're trying to find doesn't exist or isn't alive on the planet right now?

```javascript
// Love!!!!!
function hug(target) {
  target.happiness += 1000;
}

// returns undefined because Eleanor is in The Good Place
const eleanor = magicMap.get("Eleanor Shellstrop"); 

// brace yourself
hug(eleanor); // => 💥💥💥 Much explosion. 
// Cannot read property happiness of undefined
```

Yep. That's the problem right there. JavaScript just like Java, Ada and ALGOL suffers from the same ailment caused by the presence of `null`. Although in the case of JavaScript, it may be worse because we have not one but **two ways to represent the absence of value: `null` and `undefined`**.

<img width="400" class="center" src="https://www.barbarianmeetscoding.com/images/brendan-eich-glasses.gif" alt="Brendan Eich feeling awesome with sun glasses as he puts both null and undefined into JavaScript" title="Brendan Eich feeling awesome with sun glasses as he puts both null and undefined into JavaScript">

Both of these keywords represent the absence of value in JavaScript. Both will result in a *null reference exception*[^1] like the one described in the example above. So What is the difference between them? 

There are several:

* As far as I know there's no native browser API that ever returns `null`. For the web platform, the absence of value is always `undefined`.
* By convention, the community usually refers to `null` as the absence of value, whereas `undefined` represents something that hasn't yet been defined. A developer could use `null` to denote a deliberate absence of value, whereas `undefined` would be the web platform telling you that something hasn't been defined yet. `null` may be also produced by APIs when interoperating between clients and servers (e.g. Java sending JSON to a JavaScript front-end). In fact, the JSON spec only supports `null` and not `undefined`. 
* Default arguments behave differently when given `undefined` or `null`. Pass an `undefined` as an argument to your function and your function will use the default value that you provide. Pass a `null` instead and you function will use it happily instead of your default value. (Which is mighty dangerous)

For all of the above, I try to steer away from `null` as much as I can, and handle `undefined` when it's produced by the platform. But even so, there will be times when you'll have no other choice that to work around `null` and `undefined`. And they will inevitably lead you to null reference exceptions and the very classic **undefined is not a function**...

So, **How can TypeScript help us with this mess?**

## TypeScript and the absence of value

So TypeScript doesn't have two ways to represent the absence of value. **It has four**.

<img width="400" class="center" src="https://www.barbarianmeetscoding.com/images/anders-glasses.gif" alt="Anders Hejlsberg feeling awesome with sun glasses as he puts both null, undefined, void and never into TypeScript" title="Anders Hejlsberg feeling awesome with sun glasses as he puts both null, undefined, void and never into TypeScript">

These four ways to represent the absence of value are:

* `undefined` and `null` just like in JavaScript since, after all, TypeScript is a superset of JavaScript
* `void` which represent the return type of a function that doesn't return anything
* `never` which represents the return type of a function that never returns (e.g. it throws an exception instead)

Wow! Four instead of Two?? Is this something good? And the answer is **YES**. Not because of the numerous ways to represent the absence of value but because **in TypeScript `null` and `undefined` are also types**.

So What?

Let's take a look at the previous example. We define the `Target` interface to represent anything that has a `happiness` property (which is all a human, pet or monster needs to be huggable):

```typescript
interface Target {
  happiness: number;
}
```

And now we can use it in our `hug` function:

```typescript
// Love!!!!!
function hug(target: Target) {
  target.happiness += 1000;
}
```

If we try to hug sad Jaime as we did earlier everything shall be fine:

```typescript
// Love!!!!!
function hug(target: Target) {
  target.happiness += 1000;
}

const sadJaime = magicMap.get("Jaime"); // that's me of course
hug(sadJaime); // => Wihooo! ❤️
```

But what if we make the attempt to hug Eleanor?

```typescript
// Love!!!!!
function hug(target: Target) {
  target.happiness += 1000;
}

// returns undefined because Eleanor is in The Good Place
const eleanor = magicMap.get("Eleanor Shellstrop"); 

hug(eleanor); // => 💥 Argument of type 'undefined' is not assignable to parameter of type 'Target'.
```

We get an error!! We get a **compile-time** error. That is, as soon as we type the code above the TypeScript compiler will tell us that we're doing something wrong. Because the function `hug` expects a `Target` and we're giving it `undefined` which is a completely different type that doesn't have any of the characteristics of `Target`, the TypeScript compiler jumps in to help. 

**And so this is how TypeScript takes advantage of the `null` and `undefined` types to prevent you from running into null reference exceptions and the dreaded million dollar mistake**. Awesome, right?

> ### Strict Null Checking
> The behavior we've just seen, where TypeScript will prevent you from shooting yourself in the foot with null or undefined is called <strong>strict null checking</strong>. It is a feature of the TypeScript compiler which was added in TypeScript 2.0 an which needs to be enabled in your tsconfig file via the stricNullChecks setting. <strong>In general, it is strongly advised to aspire to having your TypeScript configuration be as strict as possible.</strong> That way you'll take the most advantage of TypeScript's type system and you'll be able to write safer and more maintainable applications.

Just for kicks. How could we rewrite the function above to allow for `null` or `undefined` and be equivalent to the JavaScript version? One way to do it would be the following:

```typescript
// Love!!!!!
function hug(target: Target | undefined | null) {
  target.happiness += 1000;
}
```

So we're explicitly telling TypeScript that the argument of that function can be either `Target`, `undefined` or `null` by using a [type union](/blog/2019/12/07/typescript-types-deep-dive-part-i). Or alternatively:

```typescript
// Love!!!!!
function hug(target?: Target | null) {
  target.happiness += 1000;
}
```

Where we use an optional argument using the `target?` notation which is a shorthand for `Target | undefined`.

### Working with Null or Undefined

There'll be some situations in which you'll still need to work with `null` or `undefined`. Let's say that you're working with a third party library that is implemented in JavaScript and doesn't care much about returning `null` or `undefined`. You potentially have a mighty warrior that is about to use its sword to slash some potatos for the Christmas dinner, so you write this:

```javascript
const warrior = tavern.hireWarrior({goldCoins: 2});

if (warrior !== null 
    && warrior !== undefined
    && warrior.sword !== null 
    && warrior.sword !== undefined){
  warrior.sword.slash();
}
```

The warrior hiring API you were using was written in JavaScript and you can't be sure if it even returns a warrior, or if the warrior has a sword so to be on the safe side you are forced to write a bunch of null/undefined checks.

TypeScript (>=3.7) has an alternative and less wordy version to the pattern above. The **optional chaining** operator `?.` which lets us rewrite the above example:

```typescript
warrior?.sword?.slash();
// The ? is often called the Elvis operator
// because this ?:-p
```

That is, we shall call the `slash` method *only* when the `warrior` and her `sword` are not undefined nor null. That's a much nicer alternative if you ask me.

Yet another alternative to solving the issue with the hiring a warrior at a disreputable tavern is to have a default value at hand that we can use when things go awry. So in order to make sure that the slashing above takes place we could've followed the approach of always making sure that the mighty warrior does exist:

```javascript
let warrior = tavern.hireWarrior({goldCoins: 2});
if (!warrior) {
  warrior = new Warrior('Backup Plan Joe');
}
if (!warrior.sword) warrior.equip(new RustySword());

warrior.sword.slash();
```

TypeScript also has an alternative to the check-if-this-is-null-and-if-it-is-assign-this-other-value pattern: the **nullish coallescing operator** `??`. 

Using `??` we can simplify the example above:

```typescript
let warrior = tavern.hireWarrior({goldCoins: 2}) 
              ?? new Warrior('Backup plan Joe');

if (!warrior.sword) warrior.equip(new RustySword());

warrior.sword.slash();
```

Nice right? Both `?.` and `??` operators make it that much easier to work around the absence of value in TypeScript.

>  <a href="https://github.com/tc39/proposal-optional-chaining">Optional chaining</a> and <a href="https://github.com/tc39/proposal-nullish-coalescing">the nullish coalescing operator</a> were <a href="https://github.com/tc39/proposals/blob/master/finished-proposals.md">approved as part of ES2020</a> and are now official features of the JavaScript language. Yey!

## Are There Better Ways to Model the Absence of Value?

A really cool way to model the absence of value comes from functional programming in the form of the `Maybe` monad. In later articles of the series when we've dabbled in the mysteries of generic types we'll revisit this topic and learn about how TypeScript can support these functional programming patterns.

## In Summary

`null` and `undefined` can cause havoc in your JavaScript programs. They can break things willy nilly at runtime, or they can force you into writing a lot of guard causes and defensive code that can be very verbose and obscure your core business logic. 

In TypeScript `null` and `undefined` are also types. This in combination with strict null checks allows you to protect your programs from null reference exceptions at compile time. So that, as soon as you make a mistake that could have resulted in a bug sometime along the line at runtime, you get immediate feedback and can fix it right away.

When confronted with the need to work with `null` or `undefined` TypeScript 3.7 and ES2020 have two features that can lessen your woes. **Optional chaining and the nullish coallescing operator** will save you a lot of typing when dealing with null and undefined.

And that's all for today. Hope you've enjoyed the article and learned something new. Until next time, take care and have a wonderful day.

[^1]: In JavaScript null reference exceptions are treated as the more general TypeError. There isn't a specific error that only applies to null reference exceptions like in other languages such as C# or Java (NullReferenceException).