Simplify nested object property use

Description

Sometimes we deal with deeply nested objects and we need to add extra checks to prevent our app from breaking while trying to access undefined parts of that object. Here’s a not so usual way of doing so.

Use case and improvement

Here’s a real life example that I found while reviewing code:

function isFileSizeTooLargeError(error) {
  if (!error) return false;
  if (!error.networkError) return false;
  if (!error.networkError.result) return false;
  if (!error.networkError.result.error) return false;
  return error.networkError.result.error.includes('file size too large');
}

Don’t worry too much about what’s going on, but if you want some context this is an error checking function for a GraphQL query response made with react-apollo.

For reasons that don’t matter for this post, we can’t be sure that we will have every piece of the object we are checking and we only care about the text included on the last error.

If we didn’t do any check and we just ran the includes check, we may get different exceptions, like:

  • TypeError: Cannot read property 'includes' of undefined
  • TypeError: Cannot read property 'error' of undefined

That’s why all those checks were included.

We can simplify our code by acknowledging that there may be exceptions and that we don’t care about them.

function isFileSizeTooLargeError(error) {
  let fileSizeTooLarge = false;
  try {
    fileSizeTooLarge = error.networkError.result.error.includes('file size too large');
  } catch (ignoreThisError) {
    // something went wrong, we don't care exactly why,
    // the string we look for is not there
  }
  return fileSizeTooLarge;
}

Note that this implementation has more lines of code than the previous one, but there are fewer lines that actually do something.

Any exception on this context means that the string we are looking for isn’t there, we can safely ignore it (empty catch).

Have in mind that this is no silver bullet; depending on your implementation it may be better to have several conditionals or handle different kind of exceptions.

Future

This is a well known problem and there are many ways of dealing with it. One of them is to improve Javascript itself.

There’s work being done to include a new syntax to JS that simplifies use cases like this.

The proposed change is called Optional Chaining, at the time of writing this it’s on Stage 2.

Using that syntax our code would look like this:

function isFileSizeTooLargeError(error) {
  const fileSizeTooLarge = error?.networkError?.result?.error?.includes('file size too large');
  return Boolean(fileSizeTooLarge);
}

There’s already a Babel plugin for this so you can play around with it, see https://github.com/babel/babel/pull/5813

Having said that, I don’t think you should use this now on your apps :).

Disclaimer

I wrote this article for the SpiderOak engineering blog and it was published on May 22, 2019. https://engineering.spideroak.com/simplifying-deep-object-property-getting/

The original post is licensed as: Creative Commons BY-NC-ND


01001001 01110110 01100001 01101110
00110010 00110000 00110010 00110010