Optional Chaining and Nullish Coalescing - TypeScript 3.7!!
Tags: typescript, javascript
Published: 2019-11-06 13:57:23

TypeScript is a language based on JavaScript that adds static type-checking along with type syntax. Static type-checking lets us know about problems with our code before we try to run it by reporting errors if we do something questionable.

Yesterday, 5th November, a new version of TypeScript was released. The new features include:

* Optional Chaining
* Nullish Coalescing
* Assertion Functions
* Better Support for never-Returning Functions
* --declaration and --allowJs
* More Recursive Type Aliases
* The useDefineForClassFields Flag and The declare Property Modifier
* Build-Free Editing with Project References
* Uncalled Function Checks
* Flatter Error Reporting
* // @ts-nocheck in Typescript Files
* Semicolon Formatter Option
* Website and Playground Updates
* Breaking Changes:
    * DOM Changes
    * Class Field Mitigations
    * Function Truthy Checks
    * Local and Imported Type Declarations Now Conflict
    * API Changes

We'll be looking at Optional Chaining and Null Coalescing. [Here](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7/) is a comprehensive read on all the new features.

## Optional Chaining

At its core, optional chaining lets us write code where we can immediately stop running some expressions if we run into a `null` or `undefined`. There's a new operator - `?.` for *optional property accesses*. When we write code like this

`let x = foo?.bar.baz();`

this is a way of saying that when `foo` is defined, `foo.bar.baz()` will be computed but when `foo` is `null` or `undefined`, stop what we're doing and just return `undefined`.

More plainly, that code snippet is the same as writing the following.

```TypeScript

    let x = (foo === null || foo === undefined) ?
        undefined :
        foo.bar.baz();

```

Note that if `bar` is `null` or `undefined`, our code will still hit an error accessing `baz`. Likewise, if `baz` is `null` or `undefined`, we'll hit an error at the call site. `?.` only checks for whether the value on the *left* of it is `null` or `undefined` - not any of the subsequent properties.

Keep in mind that `?.` acts differenty than those `&&` operations since `&&` will act specially on "falsy" values (e.g. the empty string, `0`, `NaN`, and, well, `false`). The new operator `?.` doesn't short-circuit on valid data like `0` or empty strings.

### Optional Element Access

Optional chaining includes *optional element access* which acts similarly to optional property accesses, but allows us to access non-identifier properties (e.g. arbitrary strings, numbers, and symbols):

```TypeScript

    /**
        * Get the first element of the array if we have an array.
        * Otherwise return undefined.
    */
    function tryGetFirstElement<T>(arr?: T[]) {
        return arr?.[0];
        // equivalent to
        //      return (arr === null || arr === undefined) ?
        //          undefined :
        //          arr[0];
    }

```

### Optional Call

This allows to conditionally call expressions if they're not `null` or `undefined`.

```TypeScript

    async function makeRequest(url: string, log?: (msg: string) => void) {
        log?.(`Request started at ${new Date().toISOString()}`);
        //  roughly equivalent to
        //      if (log != null) {
        //          log(`Request started at new ${new Date().toISOString()}`);
        //      }
        const result = (await fetch(url)).json();

        log?.(`Request finished at ${new Date().toISOString()}`);

        return result;
    }

```

The "short-circuiting" behaviour that optional chains have is limited to property accesses, calls, element accesses - it doesn't expand any further out from these expressions. In other words,

`let result = foo?.bar / someComputation()`

doesn't stop the division or `someComputation()` call from occuring. It's equivalent to

```TypeScript

    let temp = (foo === null || foo === undefined) ? undefined : foo.bar;

    let result = temp / someComputation();

```

That might result in dividing `undefined`.

## Nullish Coalescing

This introduces a new operator `??`. It is a way to "fall back" to a default value when dealing with `null` or `undefined`. When we write code like

`let x = foo ?? bar();`

this is a new way to say that the value `foo` will be used when it's "present"; but when it's `null` or `undefined`, calculate `bar()` in its place.

Again, the above code is equivalent to the following.

`let x = (foo !== null && foo !== undefined) ? foo : bar();`

The `??` operator can replace uses of `||` when trying to use a default value. For example, the following code snippet tries to fetch the volume that was last saved in localStorage(if it ever was); however, it has a bug because it uses `||`.

```TypeScript

    function initializeAudio() {
        let volume = localStorage.voume || 0.5

        // ...
    }

```

When `localStorage.volume` is set to `0`, the page will set the volume to `0.5` which is unintended. The `??` operator avoids some unintended behaviour from `0`, `NaN` and `""` being treated as falsy values.