1

Null coalescing by ORing a string (via PRIORITIES[NUM_TO_PRIORITY[priorityNum]] where priorityNum is input) and a string (via conditional Object.values(PRIORITIES).includes(priorityNum) ? priorityNum : PRIORITIES.low) should output a string yet outputs a number (matching the input). Why does this happen?

This could be a js quirk but unsure why the output is a number as testing shows coalescing should be between 2 strings to output a string:

const PRIORITIES = {
    high: 'HIGH',
    low: 'LOW',
};
const NUM_TO_PRIORITY = {
    0: 'high',
    1: 'low',
};
const priorityNum = 0;
console.log(PRIORITIES[NUM_TO_PRIORITY[priorityNum]]); // "HIGH"
console.log(Object.values(PRIORITIES).includes(priorityNum)); // false
console.log("HIGH" || false) // "HIGH" <- Expected output

// Based on the above code, the following code should output "HIGH" yet outputs 0, why does this happen?
console.log(PRIORITIES[NUM_TO_PRIORITY[priorityNum]] || Object.values(PRIORITIES).includes(priorityNum) ? priorityNum : PRIORITIES.low);
surajs02
  • 451
  • 7
  • 18

2 Answers2

3

As mentioned in another answer, it is due to operator precedence.

valOne || valTwo ? priorityNum : PRIORITIES.low;

is the same as:

(valOne || valTwo) ? priorityNum : PRIORITIES.low;

but you wanted:

valOne || (valTwo ? priorityNum : PRIORITIES.low);

Since most don't have the precedence memorized for 20+ operators, avoid these mistakes by either using more parentheses (as seen above) or more variables:

const PRIORITIES = {
    high: 'HIGH',
    low: 'LOW',
};
const NUM_TO_PRIORITY = {
    0: 'high',
    1: 'low',
};
const priorityNum = 0;

const priority = PRIORITIES[NUM_TO_PRIORITY[priorityNum]]
const otherVal = Object.values(PRIORITIES).includes(priorityNum) ? priorityNum : PRIORITIES.low

priority || otherVal; // "HIGH"
twharmon
  • 4,153
  • 5
  • 22
  • 48
2

|| has higher operator precedence than ?, so your code is evaluated as

(PRIORITIES[NUM_TO_PRIORITY[priorityNum]] || Object.values(PRIORITIES).includes(priorityNum))  ? priorityNum : PRIORITIES.low

const PRIORITIES = {
    high: 'HIGH',
    low: 'LOW',
};
const NUM_TO_PRIORITY = {
    0: 'high',
    1: 'low',
};
const priorityNum = 0;
console.log(PRIORITIES[NUM_TO_PRIORITY[priorityNum]]); // "HIGH"
console.log(Object.values(PRIORITIES).includes(priorityNum)); // false
// "HIGH" || false // "HIGH" <- Expected output

// Based on the above code, the following code should output "HIGH" yet outputs 0, why does this happen?
console.log(PRIORITIES[NUM_TO_PRIORITY[priorityNum]] || Object.values(PRIORITIES).includes(priorityNum) ? priorityNum : PRIORITIES.low);
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
  • agreed that `||` has higher precedence but shouldn't that mean it becomes `(PRIORITIES[NUM_TO_PRIORITY[priorityNum]] || Object.values(PRIORITIES).includes(priorityNum))` which resolves to `"HIGH" || false` which should output `"HIGH"`? – surajs02 Apr 14 '20 at 17:01
  • @surajs02 no which resolves further to "HIGH" ? priorityNum : PRIORITIES.low and finally resolves down to 0 – Code Maniac Apr 14 '20 at 17:03
  • sorry, didn't see the brackets added, `?` resolving after `||` makes sense, thanks, will accept the answer :) – surajs02 Apr 14 '20 at 17:06