DEV Community

Obinna Ogbonna
Obinna Ogbonna

Posted on

Optional Chaining and Nullish Coalescing - TypeScript 3.7!!

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 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.


    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):


    /**
        * 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.


    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


    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 ||.


    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.

Oldest comments (2)

Collapse
 
kenzdozz profile image
Kenneth Chidozie

Nice one man...

Collapse
 
obinnaogbonnajoseph profile image
Obinna Ogbonna

Thanks!šŸ¤—