freefaller
freefaller

Reputation: 19953

Get boolean property, or default true if it doesn't exist

In javascript, is there a better way to get the value of a boolean property on an object, but default to true if the property doesn't exist, than below?

 (typeof myObj.myProp !== "undefined" ? myObj.myProp : true);

I feel there must be a better way of doing it.

Test cases...

 myObj = {}; // return true
 myObj = { myProp: false; } // return false;
 myObj = { myProp: true; } // return true

Upvotes: 0

Views: 694

Answers (1)

VLAZ
VLAZ

Reputation: 28970

ECMAScript 2020 introduced the nullish coalescing operator ??:

const test = obj =>
  obj.myProp ?? true;

console.log( test({}) );                // return true
console.log( test({ myProp: false }) ); // return false
console.log( test({ myProp: true }) );  // return true

However, before that existed there is not many options. Your current code (typeof myObj.myProp !== "undefined" ? myObj.myProp : true) is probably the best you can have for older environments.

If you do have to deal with them a lot and nullish-ness is a constant problem, you can make a simple wrapper for safely getting values that might not exist:

function Safe(val) {
  return {
    get: function(prop) {
      if (val == null)
        return Safe(null);
        
      return Safe(val[prop]);
    },
    orElse: function(fallbackValue) {
      if (val == null)
        return fallbackValue;

      return val
    }
  }
};

console.log( //true
  Safe({})
    .get("myProp")
    .orElse(true)
)
console.log( // false
  Safe({ myProp: false })
    .get("myProp")
    .orElse(true)
);
console.log( // true
  Safe({ myProp: true })
    .get("myProp")
    .orElse(true)
);

var complexObject = {
  level1: {
    level2: {
      myProp: false
    }
  }
};

console.log( // { "level2": { "myProp": false } }
  Safe(complexObject)
    .get("level1")
    .orElse(true)
);
console.log( // { "myProp": false }
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .orElse(true)
);
console.log( // false
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .get("myProp")
    .orElse(true)
);
console.log( // true
  Safe(complexObject)
    .get("level1")
    .get("level2")
    .get("level3")
    .get("myProp")
    .orElse(true)
);
.as-console-wrapper { max-height: 100% !important; }

The API here modelled after Java's Optional but very simplified. The point is to show that it is possible to do safer handling if that is something that often shows up.

The Optional in Java is also called Option or Maybe in other places and more formally encodes handling values that might be null. To see the more of how this can be done, see this chapter of Mostly Adequate Guide to Functional Programming on GitBooks (or the older version which uses ES5 syntax)

Another alternative instead of writing your own safe handling would be to use a library that supports it like Lodash's _.get():

console.log( //true
  _.get({}, "myProp", true)
);
console.log( // false
  _.get({ myProp: false }, "myProp", true)
);
console.log( // true
  _.get({ myProp: true }, "myProp", true)
);

var complexObject = {
  level1: {
    level2: {
      myProp: false
    }
  }
};

console.log( // { "level2": { "myProp": false } }
  _.get(complexObject, "level1", true)
);
console.log( // { "myProp": false }
  _.get(complexObject, [ "level1", "level2"], true)
);
console.log( // false
  _.get(complexObject, [ "level1", "level2", "myProp"], true)
);
console.log( // true
  _.get(complexObject, [ "level1", "level2", "level3", "myProp"], true)
);
.as-console-wrapper { max-height: 100% !important; }
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Upvotes: 2

Related Questions