Operator precedence of nullish coalescing and ternary

Viewed 1100

Can someone explain why result evaluates to 20 in this statement?

let result = 10 ?? true ? 20 : 30;

Given nullish coalescing evalutes the statement in a left-to-right manner and is of higher precedence than a ternary operator, why is it safe to not assume that result should be 10?

Note: if a grouping operator is added, then result is 10.

let result = 10 ?? (true ? 20 : 30);
3 Answers

As I understand it, a nullish coalescing operator (??) has a higher operator presedence than a conditional (ternary) operator, so it should execute first.

(The docs say that ?? operator has an operator precedence score of 5, while ... ? ... : ... has a score of 4.)

So

let result = 10 ?? true ? 20 : 30;

basically evaluates to

let result = (10 ?? true) ? 20 : 30; // => 10 ? 20 : 30

And given that 10 is a truthy value, it (10 ? 20 : 30) evaluates to 20

Extra details

You may notice that there is an "Associativity" column in the JavaScript table of operator presedence.

And you may wonder if it plays a role in this case. But the answer to that seems to be that it doesn't. And that's stated in the following quote (from the docs):

The difference in associativity comes into play when there are multiple operators of the same precedence.

Source

As stated above in blex's comment, the statement simply reduces the coalescing operation to the value 10, then evaluates 10 ? 20 : 30. Since 10 is a truthy value, the ternary operation here will return the true case, which is 20.

There will be no case where you combine nullish coalescing and ternary. Have a look at this example:

a ?? false ? 'foo' : 'bar'

If a is truthy, then a is picked, and 'foo' is obviously returned.
If a is nullish, i.e. null, undefined, then false is picked, and 'bar' is returned.
If a is of other falsy values, i.e. '', 0, false, then a is picked. However, a is still falsy in the perspective of the ternary, therefore 'bar' is returned.
If you want to bring nullish check to a conditional statement, instead use:

a != null ? 'foo' : 'bar' // a is not null or undefined
!a && a != null ? 'bar' : 'foo' // a is not '', 0, or false. Does anyone really use this one?
Related