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.

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
If0
or''
orfalse
or0n
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!