Use the Nullish Coalescing Operator over Ternary or Logical-or Operators
Monday, August 17, 2020
Use the Nullish Coalescing Operator over Ternary or Logical-or Operators
The nullish coalescing operator was introduced in the ECMAScript 2020 specification as a binary operator, which for most JavaScript developers replaces the use of the logical-or operator for setting a default/fallback value.
Logical Or
Prior to ECMAScript 2020 there were two common approaches to a binary operation with a default/fallback value, either the logical-or operator, or the ternary operator. Let's look at both of these.
First, let's look at how the logical-or operator can be used with a fallback value.
interface Props {
score: number;
}
export default ({ score }: Props) =>
<div className="score">{ score || '-' }</div>;
Breaking this down:
- Our component expect a
score
prop, which will display the score of the game. - If the score value is not provided we use the logical-or operator to display a dash ( - ), likely indicating that the game has not yet started.
The benefits of this approach are:
- A boolean test is performed on the
score
value, and if the boolean test results infalse
, then the right side of the logical-or operator is the result of the expression. - If the boolean test result is
true
, then the left side of the logical-or operator is the result of the expression. - The value is only evaluated once. Below we'll see how this compares to using the ternary operator.
Therefore, if the score
value is "truthy", then the score is rendered, and if the value is "falsey", then the dash ( - ) is rendered.
However, there is a foot gun to this approach. If the score
value is 0
(or falsey), then the boolean test results in false
, and the right-hand side of the logical-or operator is the result of the expression.
Ternary Operator
A second common method for a binary operation is the ternary operator. Let's look at our same Score
component using this approach:
interface Props {
score: number;
}
export default ({ score }: Props) =>
<div className="score">{ score ? score : '-' }</div>;
In this example we are using the ternary operator where a boolean test is performed on the score
value, and if true
, then the result of the expression is the evaluation of the code that is on the left side of the colon ( : ). And, if the boolean test result is false
, then the result of the expression is the evaluation of the code on the right side of the colon ( : ).
The potential problem with the ternary operator approach is that the value, score
in this example, is evaluated twice. First, it is evaluated as part of the boolean test, and then again, as the result of the expression if the boolean test is true
. While in this particular example that may not be issue, this could be an issue if the value under assertion is a function, and further, if the value under assertion performs a side effect.
It should be noted that using the ternary operator approach we can avoid the foot gun we observed in the logical-or approach, namely, we can explicitly check the value. For example:
interface Props {
score: number;
}
export default ({ score }: Props) =>
<div className="score">{ (score !== null || score !== undefined) ? score : '-' }</div>;
By explicitly checking the value of score
to be either null
or undefined
we can ensure that the score of 0
is rendered properly.
This brings us to the conclusion of the necessity for a succinct method for asserting a value to be not null
or not undefined
with a default/fallback value for the expression.
Nullish Coalescing
While the name in itself may be confusing, the nullish coalescing operator introduced in ECMAScript 2020 is currently widely adopted by browsers and provides for a succinct method for asserting a value is not null
or undefined
with a fallback value for the expression.
Let's look at an example using the nullish coalescing operator:
interface Props {
score: number;
}
export default ({ score }: Props) =>
<div className="score">{ score ?? score : '-' }</div>;
This looks very similar to the first approach of the logical-or operator, and also quite similar to the ternary operator.
Here, we use the nullish coalescing operator (two question marks) to output the score
value as long as the value is not null
or undefined
. This code is equivalent to the previous example of the ternary operator where we checked for null
and undefined
with the exception that the value is not evaluated twice. This avoid the potential issue with the ternary operator approach of evaluating the value twice, and the potential of invoking side effects unecessarily.
Instructions
use the nullish coalescing operator for effective and succinct binary operations with a fallback value
the logical or operator for fallback values
the ternary operator for fallback values
Code Examples
use the nullish coalescing operator for binary operations with a fallback value
let a = b ?? c; // ✅ effective and succinct check for null and undefined with a fallback value
the logical or operator for fallback values
let a = b || c; // ⚠️ b could be a falsey value and result erroneous in the fallback value of c
the ternary opeerator for fallback values
let a = b ? b : c; // ⚠️ b is evaluated twice
the ternary operator for fallback values
let a = (b !== null && b !== undefined) ? b : c; // ⚠️ b is evaluated twice
Have a question or comment?
Hello, Thank you for this article, it's very well explained
I think there is little a mistake in your nullish coalescing operator example:
this :
<div className="score">{ score ?? score : '-' }</div>;
Should be
<div className="score">{ score ?? '-' }</div>;