Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I check if multiple properties exists on an object without being too verbose?

Tags:

javascript

I am trying to verify that some properties exist on a configuration object and have values (truthy? not necessrily as a few pointed out in the comments) in javascript in the following manner:

const verifyJanrainAppSettings = (options) => {
    return options.JanrainAppSettings
      && options.JanrainAppSettings.settings.tokenUrl
      && options.JanrainAppSettings.settings.capture.clientId
      && options.JanrainAppSettings.settings.capture.appId
      && options.JanrainAppSettings.settings.capture.appDomain
      && options.JanrainAppSettings.settings.capture.captureServer
      && options.JanrainAppSettings.settings.httpLoadUrl
      && options.JanrainAppSettings.settings.httpsLoadUrl
}

I feel this is too verbose and I am curious if there is a better pattern. Perhaps something like if (['my', 'options'] in myObject) ...

like image 818
awm Avatar asked Jul 24 '20 16:07

awm


3 Answers

You can keep a reference to settings, which improves things a fair bit:

const verifyJanrainAppSettings = (options) => {
    const settings = options.JanrainAppSettings && options.JanrainAppSettings.settings;
    return settings &&
      settings.tokenUrl &&
      settings.capture && // ** This was missing in the question, but I think you need it
      settings.capture.clientId &&
      settings.capture.appId &&
      settings.capture.appDomain &&
      settings.capture.captureServer &&
      settings.httpLoadUrl &&
      settings.httpsLoadUrl;
};

While you could put some of those names in an array and use a loop, I think I'd leave it at that.

With optional chaining (new in ES2020), that first line could be:

    const settings = options.JanrainAppSettings?.settings;

The array version would look something like:

const settingsProps = "capture tokenUrl httpLoadUrl httpsLoadUrl".split(" ");
const captureProps = "clientId appId appDomain captureServer".split(" ");
const verifyJanrainAppSettings = (options) => {
    const settings = options.JanrainAppSettings && options.JanrainAppSettings.settings;
    return settings &&
      settingsProps.every(prop => settings[prop]) &&
      captureProps.every(prop => settings.capture[prop]);
};

adiga asks a good question. If you want existence rather than truthiness (you have truthiness in your question), you'll want in (or for an own property check, hasOwnProperty). For instance:

const settingsProps = "capture tokenUrl httpLoadUrl httpsLoadUrl".split(" ");
const captureProps = "clientId appId appDomain captureServer".split(" ");
const verifyJanrainAppSettings = (options) => {
    const settings = options.JanrainAppSettings && options.JanrainAppSettings.settings;
    return settings &&
      settingsProps.every(prop => prop in settings) &&
      captureProps.every(prop => prop in settings.capture);
};
like image 169
T.J. Crowder Avatar answered Oct 24 '22 17:10

T.J. Crowder


I would opt for an utility function:

function contains(object, ...keys) {
  return keys.every((key) => key in object)
}

const verifyJanrainAppSettings = (options) => {
  return (
    contains(options.JanrainAppSettings, 'settings') &&
    contains(
      options.JanrainAppSettings.settings,
      'tokenUrl',
      'httpLoadUrl',
      'httpsLoadUrl',
      'capture'
    ) &&
    contains(
      options.JanrainAppSettings.settings.capture,
      'clientId',
      'appId',
      'appDomain',
      'captureServer'
    )
  )
}

like image 24
lhrinaldi Avatar answered Oct 24 '22 16:10

lhrinaldi


Perhaps something like if (['my', 'options'] in myObject) ...

This is the right idea. However, you need to loop over the array of strings and check if each of them is in myObject. You can do this loop with Array.every(). The only disadvantage is this only works at the deepest level. Since you have several levels of nesting here it will still get kind of ugly:

const verifyJanrainAppSettings = (options) => {
    return options.JanrainAppSettings
      && options.JanrainAppSettings.settings // dont' forget this check
      && ['tokenUrl', 'httpLoadUrl', 'httpsLoadUrl', 'capture'].every(key => // added options.JanrainAppSettings.settings.capture check
        key in options.JanrainAppSettings.settings
      )
      && ['clientId', 'appId', 'appDomain', 'captureServer'].every(key =>
        key in options.JanrainAppSettings.settings.capture
      );
}
like image 35
Code-Apprentice Avatar answered Oct 24 '22 18:10

Code-Apprentice