Javascript Operators - Combining Nullish Coalescing with Ternary

July 20, 2021, at 7:50 PM

So I have some code where I'm essentially trying to do an if, else if, else statement in one line, but based on nullishness instead of truthiness.

Say I have a boolean value "status" on a person object:

let person = {
  status: true

I want to show text based on the following conditions:

  • True: 'Verified'
  • False: 'Not Verified'
  • Doesn't exist: 'Loading...'

I could use the ternary operator like this:

person?.status ? 'Verified' : 'Not Verified'

But if the person object doesn't exist, or if the "status" field doesn't exist, it will return a falsey value.

If I use the nullish coalescing operator like this:

person?.status ?? 'Loading...'

I can get the desired result in very condensed and readable code, but there is no way to format the text without using a helper function.

Is there anyway to combine these into one line of readable code, or am I stuck having a write a helper function or using a longer line of code like this:

person?.status == null ? 'Loading...' : (person.status ? 'Verified' : 'Not Verified')

Maybe I'm being picky, but I'm just wondering if someone out there has a more optimal, condensed way of doing this.

Thanks for your help!

Answer 1

I'm just wondering if someone out there has a more optimal, condensed way of doing this.

You have this backwards. More condensed is not more readable. The more operations are in one line the harder it is to figure out what it does:

a ?? b ? c ?? d?.e : f || x

Is much harder to parse mentally than if it wasn't all in one line. Among other things, you need to keep in mind the order of operations - does the OR mean (f || x) or is it OR-ing the entire expression up to there?

It will be resolved as (a ?? b ? c ?? d?.e : f) || x. Yet it hardly helps with evaluating this in your head.

The more optimal and readable way of writing this would be using regular if/else statements

let status;
if (person?.status == null)
    status = 'Loading...';
else if (person.status)
    status = 'Verified';
    status = 'Not Verified';

If needed, it can be encapsulated in a function.

function status(person) {
    if (person?.status == null)
        return 'Loading...';
    if (person.status)
        return 'Verified';
    return 'Not Verified';

If you really need something short to use, you can have a simple lookup table that resolves the different possible values:

const lookup = {
    "null" : 'Loading...',
    "true" : 'Verified',
    "false": 'Not Verified',
/* ... */
const status = lookup[person?.status ?? null];

Also possible: drop the nullish coalescing operator and encode the undefined in the lookup:

const lookup = {
    "null"      : 'Loading...',
    "undefined" : 'Loading...',
    "true"      : 'Verified',
    "false"     : 'Not Verified',
/* ... */
const status = lookup[person?.status];

This is mostly irrelevant but somewhat fun. You can combine a lookup and a function to make a fairly minimal function that does not use if/else or switch-es to determine what to return:

const status = person => ({
    "null"      : 'Loading...',
    "undefined" : 'Loading...',
    "true"      : 'Verified',
    "false"     : 'Not Verified',
console.log( status() );                //Loading...
console.log( status(null) );            //Loading...
console.log( status({}) );              //Loading...
console.log( status({status: true}) );  //Verified
console.log( status({status: false}) ); //Not Verified

It is not the best practice but can be handy occasionally. It can aid prototyping things. It is then an easy refactor to extract the object out of the function which in turn would allow you to load it from configuration, for example. In this case it might help with translating this to different languages if you have something like

  'english': {
        "null"      : 'Loading...',
        "undefined" : 'Loading...',
        "true"      : 'Verified',
        "false"     : 'Not Verified',
  'pig-lating': {
        "null"      : 'Oadinglay...',
        "undefined" : 'Oadinglay...',
        "true"      : 'Erifiedvay',
        "false"     : 'Otnay Erifiedvay',
Django - JQuery autocomplete custom select from multiple fields

Django - JQuery autocomplete custom select from multiple fields

I have a user search that autocompletes by both ticker and nameThe search results come back as "{{ticker}} - {{name}}"

How good implement method? [closed]

How good implement method? [closed]

Want to improve this question? Update the question so it's on-topic for Stack Overflow