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