DEV Community

Cover image for I do this all the time to reduce bugs in my javascript code #1
Kati Frantz
Kati Frantz

Posted on • Originally published at katifrantz.com

I do this all the time to reduce bugs in my javascript code #1

Have a look at the following code sample:

data.course.enrolments.forEach(enrolment => enrolment.confirm())
Enter fullscreen mode Exit fullscreen mode

Sometimes the data we work with is not predictable, so to avoid errors or crashes we always have to take care of edge cases. The above code makes a lot of assumptions. It assumes that data.course exists, data.course.enrolments exists and is an array of objects with a confirm property which is a valid Function.

If the data.course or data.course.enrolments property is undefined we get the following TypeError error:

Uncaught TypeError: Cannot read property enrolments of undefined
Uncaught TypeError: Cannot read property forEach of undefined
Enter fullscreen mode Exit fullscreen mode

If the confirm property in each enrolment object in the data.course.enrolments array is not a valid Function, we get the following error:

Uncaught TypeError: enrolment.confirm is not a function
Enter fullscreen mode Exit fullscreen mode

Now have a look at this one:

((data.course || {}).enrolments || [])
    .forEach(enrolment => enrolment.confirm && enrolment.confirm())

Enter fullscreen mode Exit fullscreen mode

I'll explain how the above snippet works.

data.course || {}

This expression resolves to data.course if the course property exists on the data object, and resolved to an {} if it doesn't. The reason it resolves to {} is because of the || operator which checks if the left-hand side of the expression (data.course) is falsy, and if it is, resolves the expression to the right-hand side ({}). If it's not falsy then it resolved the expression to the left-hand side.

(data.course || {}).enrolments || [])

As explained above, the left-hand side will either be data.course or {}. Next, we try to access the enrolments property on the object resolved from the first expression.

enrolment.confirm && enrolment.confirm()

Unlike the || operator, the && checks if the left-hand side of the expression (enrolment.confirm) is truthy, and if it is, resolves the expression to be the right-hand side (enrolment.confirm()). This means the function enrolment.confirm will never be executed if the confirm property is not found on the enrolment object.

Summary

Taking care of edge cases as you write your code can save you a lot of debugging time, and also prevent unexpected application crashes.

Oldest comments (6)

Collapse
 
evanplaice profile image
Evan Plaice • Edited

FYI. There is an 'Optional Chaining' TC39 proposal that suggests adding this capability as a standard, built-in feature of JS.

Ex

data.course?.enrolments?
  .forEach(enrolment => enrolment.confirm?())
Collapse
 
bahdcoder profile image
Kati Frantz

Wow this is interesting. Thanks for sharing this Evan !

Collapse
 
evanplaice profile image
Evan Plaice

Sure thing. The proposal is at Stage 2 which is promising. It means there are devs actively working out the kinks in the spec. If it lands it'll probably be available in a few years.

If you're interested in how new JS features become standards, check out github.com/tc39.

If you have feedback. Jump into the issues for a proposal. There's no gatekeep to participation.

BTW, nice tip 👍. I'll have to put this to use.

Collapse
 
dyllandry profile image
Dylan Landry • Edited

That's pretty smart. It reminds me of the style vs readability balancing act. And I wonder how often this would come in handy. It would be nice in TypeScript where accessing any possible null types can throw linting errors. I'll use this next time I run into a similar problem. Thanks for sharing!

Collapse
 
tolumide_ng profile image
Tolumide

Just applied this:
const details = { email, password } && username && { email, password, username };

Collapse
 
jayatulsiani profile image
jayatulsiani

Thank you so much for this!!