Our content is free thanks to ag-Grid

ag-Grid is the industry leading JavaScript datagrid

ag-grid.com

Double Question Marks TypeScript 3.7 - Nullish Coalescing

Post Editor

Explores the functionality and use cases of the Nullish Coalescing operator (??) that was added in TypeScript 3.7.

3 min read
post

Double Question Marks TypeScript 3.7 - Nullish Coalescing

Explores the functionality and use cases of the Nullish Coalescing operator (??) that was added in TypeScript 3.7.

post
post
3 min read
3 min read

Hi folks. I wanted to take this opportunity to talk about one of the new features of TypeScript 3.7 which, conveniently, will also be included in vanilla JavaScript.

The feature is called Nullish Coalescing and it’s summed up here by the good folks at TypeScript. But if you’re a glutton for punishment, please read on.

Nullish Coalescing

I’m sure we’d all appreciate a bit more coalescing in the world, but for now we can settle for it in our code. Exactly what is Nullish Coalescing and why do we need it?

The answer is, it’s similar to this:

const mayBeThisThingOrThisOtherThingIfNot = thisThing || thisOtherThing

but not exactly.

If you’re familiar with C# then you may have used these operators before and you can most likely tune out now and go and catch the latest episode of <insert your favorite Netflix binge here>.

If you’re still here, let’s look at how operator in question differs from the above code. Well, for a start, you’d write it like this instead:

const mayBeThisThingOrThisOtherThingIfNot = thisThing ?? thisOtherThing

If 0 or '' or false or 0n or any of those other conditions specified above could be considered valid, then use the Coalesce Nullish operator — ??. Otherwise, || will be fine and may actually give you desired functionality.

Let’s break both of these down into their verbose alternatives:

const mayBeThisThingOrThisOtherThingIfNot = thisThing || thisOtherThing

could translate to:

if (thisThing != 0 && 
    thisThing != undefined && 
    thisThing != false && 
    thisThing != '' && 
    thisThing != null && 
    thisThing != NaN && 
    thisThing != 0n) {
    
    const isThisThing = thisThing; // do stuff with isThisThing;
} 
else {
    const isThisOtherThing = thisOtherThing; // do stuff with isThisOtherThing
}

whilst

const mayBeThisThingOrThisOtherThingIfNot = thisThing ?? thisOtherThing

could be written as

if (thisThing != null && 
    thisThing != undefined) {
	
    const isThisThing = thisThing; // do stuff with isThisThing;
} else {
	
    const isThisOtherThing = thisOtherThing; // do stuff with isThisOtherThing
}

Holy difference in conditions, Batman! Of course, we as Type/JavaScript developers are one hundred percent accustomed to working with falsy values (or truthy s’il vous plaît) and would never be caught out by the old zero is a valid value chestnut. But some of you coming from other languages could be forgiven for doing so. So here’s a tip:

If 0 or '' or false or 0n or any of those other conditions specified above could be considered valid, then use the Coalesce Nullish operator — ??. Otherwise, || will be fine and may actually give you the functionality you desire.

Okay, so now we get what this operator is used for at runtime, but this is supposed to be an article about Typescript — I see no Typescript here. All right, you’re going to keep me honest. Cheers. Let’s get to it then.

Let’s take a look at what happens to our types when we use this operator. To do this, we’ll try to write a semi-quasi-real world scenario as opposed to the dodgy stuff I’ve plonked in above.

First, I’ll show you how I probably wouldn’t use this operator.

Let’s say we have a function that returns the state of something given an ID:

function getState(id: number) {
	
    const stateId = id ?? '123'
    
    return this.database.find(stateId) 
    // compilation error if this.database.find requires number
}

Here, TypeScript will not compile if this.database.find requires a number for its id argument because the type of stateId is number | '123'. What I’m pointing out is that it may not be wise or useful to use this operator with two different types on either side as Type Guards would have to be employed to handle the different possible types.

A more common and, dare I say, the intended use for this operator is to initialize variables with default values if specific values are not provided. Take the above scenario again, only this time we’ll use the same type on both sides.

function getState(id: number) {
	
    const defaultStateId = 1;    
    const stateId = id ?? defaultStateId;
    
    return this.database.find(stateId)    // no compilation error thrown
}

Note that we are not using the || operator here, as zero (0) may be considered a valid ID, so, if we did use || we’d observe the default state being returned when we really want the zeroth one!

That pretty much wraps up the explanation on this handy little operator. We already had a similar one in ||, but this one takes care of the few edge cases highlighted here, when valid values overlap the conditions covered by the || operator. Enjoy!

Discuss with community

Share

About the author

author_image
Robert Dempsey

Husband, Father and Software Engineer. Writing about challenges I've faced at work and how my team and I have overcome them.

author_image

About the author

Robert Dempsey

Husband, Father and Software Engineer. Writing about challenges I've faced at work and how my team and I have overcome them.

About the author

author_image
Robert Dempsey

Husband, Father and Software Engineer. Writing about challenges I've faced at work and how my team and I have overcome them.

NxAngularCli
NxAngularCli
NxAngularCli

Featured articles

RxJSpost
21 January 20214 min read
RxJS in Angular: Part III

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

RxJSpost
21 January 20214 min read
RxJS in Angular: Part III

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

Read more
RxJSpostRxJS in Angular: Part III

21 January 2021

4 min read

In my previous two articles we have discussed how to change our components which solve problems in imperative ways to do that in functional, reactive, RxJS way, and we of course had a lot of fun doing that.

Read more
Angularpost
20 January 20216 min read
Angular and SOLID principles

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Angularpost
20 January 20216 min read
Angular and SOLID principles

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Read more
AngularpostAngular and SOLID principles

20 January 2021

6 min read

In software engineering, making things work the first time is always easy. But, what if you want to add new functionalities to an existing code? Making iterations on an existing basis can be difficult to do without introducing bugs. This is where SOLID principles come into play.

Read more
Angularpost
14 January 20216 min read
Demystifying Taiga UI root component: portals pattern in Angular

Just before new year we announced our new Angular UI kit library Taiga UI. If you go through Getting started steps, you will see that you need to wrap your app with the tui-root component. Let's see what it does and explore what portals are and how and why we use them.