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

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.

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

THIS AD MAKES CONTENT FREE

Make Angular CLI faster

Learn how

Featured articles