DEV Community

loading...

Prevent Object Retrieval TypeError with &&

samanthaming profile image Samantha Ming ・4 min read

Code Tidbit by SamanthaMing.com

When you retrieve an object value that’s undefined, it will crash due to a TypeError! So make sure you do an initial check with an if statement. Better yet, refactor this using && 👍

Using && in this way is sometimes called the Guard Operator because the 1st expression safeguards the 2nd expression. In other words, only if the 1st expression is truthy, then will the 2nd expression be evaluated.

const forest = {}

forest.tree // undefined
forest.tree.seed // TypeError 😱


// This will prevent the TypeError but...
if(forest.tree) {
  forest.tree.seed
}

// ✅Much better using &&
forest.tree && forest.tree.seed // undefined

Understanding the && Operator

I always thought the && was just used for boolean checks like this:

if(a && b) {
  // do something
}

I never thought you can use && to evaluate to something or produce some sort of value. So when I first learned of this Guard Operator, I was super confused. So don't worry if you are too. It will take some time to understand this. The resource that helped me finally understand this is Kyle Simpson's "You Don't Know JavaScript" book.

How he describes it is think of && not just as logical operator but Selector Operators. They don't result in a boolean value or logic value. Instead, the result is always one of the two expressions. In his words, they select one of the 2 operands' values.

The value produced by a && or || operator is not necessarily of type Boolean. The value produced will always be the value of one of the two operand expressions.

Before you throw in the towel, let's take a look at an example:

const truthy = true;
const falsy = false;
const money = '💰';

truthy && money; // '💰'
falsy && money; // false

So money will be selected if the 1st expression (left side) is truthy. Otherwise, the 1st expression will be selected and the 2nd expression (right side) won't be evaluated. This is what's called Short-circuit evaluation because the 2nd expression is never evaluated.

And here's the definition from Kyle Simpson's "You Don't Know JS" book:

The right-hand operand will not be evaluated if the left-hand operand is sufficient to determine the outcome of the operation. Hence, the name "short circuited" (in that if possible, it will take an early shortcut out).

Truthy Value

So essentially the 1st expression (left side) is your truth checker. If it's true, then your 2nd expression (right side) will be selected. If your 1st expression is false, then the 1st expression's value will be used. In order to understand what's truthy, let's go over it 🤓

The truthy value list is quite an extensive one. So instead of remembering what's truthy. It's a lot easier to just remember the falsy list. And whatever is not on falsty list, is considered truthy 👍 (I wrote another blog post on Falsy Values, which you can read it here)

// JS Essentials: Falsy Values

false
undefined
null
NaN
0 or +0 or -0
"" or '' or `` (empty string)

// Everything else is truthy

Refactoring if conditionals with &&

Let's look at another example to see how the guard operator can also be useful to refactor conditional statements.

const steak = '🥩'
function cook() = {...}

// Most people use `if`
if(steak) {
  cook()
}

// Refactored using &&
steak && cook(); // `cook` only gets called if `steak` is true

Here's a good one to think about this:

someCondition && doSomething()

Thanks: @marcdel

Proposal Optional Chaining

So this is really exciting. The EcmaScript folks or the JavaScript committee is proposing an "Optional Chaining" syntax. When I was working in C#, this was such a game changer for me. I always wished JavaScript would have something similar. Really hope this proposal goes through 🙌

Rewriting our example with the Proposed Optional Chaining Syntax 🤩:

// Current
forest.tree && forest.tree.seed

// Proposal
forest.tree?.seed

DO NOT use this in your app, this is currently NOT supported.

Read more about the proposal here.


Resources


Thanks for reading ❤
Say Hello! Instagram | Twitter | Facebook | Medium | Blog

Discussion (18)

pic
Editor guide
Collapse
moopet profile image
Ben Sinclair

This is something you see a lot when stringing shell commands together.

mkdir my_directory && cd my_directory || exit(1)

This way of using && before running a function (or command) and calling it a "guard operator" makes it seem like it's not what it actually is (an expression).

It gets a little odd when you try to do things that seem to make sense on the face of it, like use an assignment instead of a final expression:

foo = {};

foo.bar || "hello";
// "hello"

console.log(foo.thisworks = "hello")
// "hello"

foo.bar || foo.bar = "hello";
// Invalid left-hand side in assignment

foo.bar && foo.baz = "hello";
// Invalid left-hand side in assignment

foo.bar && (foo.baz = "hello");
// "hello"

And it can be tempting to string too many of them together and make quite a confusing line.

I prefer to be explicit, and to dive out if the condition isn't met:

function do_the_foo(foo) {
  if (typeof foo.bar == "undefined") {
    // handle stuff or...
    return;
  }

  // continue...
  console.log(foo.bar.baz);
}
Collapse
tdubs profile image
Thom W

Maybe 'Gate' would be a better word?

Collapse
drbearhands profile image
DrBearhands

Why would one prefer the && operator over a conditional? At first glance, the later seems 'better' in many ways:

  • closer to truth
  • less language-dependent, especially if you use if (x.y !== undefined)
  • better control flow, as x.y && will result in undefined if x.y is undefined, rather than entering an else clause

It's a one-liner, sure, but I would argue ternary operators are a better fit: x.y ? f(y) : g() over (x.y && f(y)) || g().

Not saying you're wrong, but I'm curious about the reasoning.

Collapse
samanthaming profile image
Samantha Ming Author • Edited

That’s the really interesting thing about JS or programming in general. There are always multiple ways of solving things. Some of them are definitely a syntactic choice. I’m always in the camp of expanding my toolkit so when I run across it (especially from others code), I know what’s going on. But at the end of the day, you’re the owner of your code, so pick the way that makes the most sense to you 😊

Collapse
hjess profile image
Howard Jess

I'm in agreement with those opposing this idiom. The Javascript phrase:


obj && obj.prop && obj.prop.send();

is an expression, and (to me at least) should be pure, like a pure function. As used above, this expression is used only for its side effect. I would always prefer to be explicit. I like the proposed optional chaining; but until that's available, write this statement in English:


// pedantic
if (obj && obj.prop && typeof obj.prop.send === 'function') {
obj.prop.send();
}

Collapse
qm3ster profile image
Mihail Malo • Edited

Is it just me, or does it feel like the elvis operator will only enable us to be more negligent?
Nothing stops us writing

const d = a?.b?.c?.d
if (d) doStuff(d)

when what we really needed was

const d = a.b?.c.d
if (d) doStuff(d)

Which will make the code not "fail fast", even though there's no correct logic when the a has no b or a present c has no d.

The currently possible code:

const {c} = a.b
if (c) doStuff(c.d)

tells us a lot more about the structure. And it's not a token longer!

The main problem here is that a 3-level destructuring is seen as "showing off" most of the time, and (often correctly) shamed as "unreadable", here one can just say this is "defensive programming". Which it's not, since you are failing to throw valuable errors in the "safe" inner code.

So, I am sure there are genuine uses, I have many places in my code I'd like to use it myself, especially the ?.(). But I fear it will be overused, and its overuse "well-justified".

Collapse
samanthaming profile image
Samantha Ming Author

You’re absolutely right! It’s one of those common JS saying, just because you can doesn’t mean you should. When it’s used appropriately, it’s super helpful. And if you abuse it, it becomes a code smell. Definitely something to be careful of. Thanks for pointing that out 👍

Collapse
misterwhat profile image
Jonas Winzen

You could use OR defaulting to protect against Type Errors, too:

(((obj||{}).prop1||{}).prop2||{}).prop3

Or take this a step further and write a helper for this:

(iterative version)

const getObjPath = (path = []) => obj => {
  let currentVal = obj;
  for (const prop of path) {
    currentValue = (currentVal || {})[
      prop
    ];
    if (!currentValue) {
      return currentValue;
    }
  }
  return currentValue;
};

(recursive version)

const getObjPath = ([
  prop,
  ...path
] = []) => (obj = {}) =>
  path.length && obj[prop]
    ? getObjPath(path)(obj[prop])
    : obj[prop];

Collapse
samanthaming profile image
Samantha Ming Author

I typically use the “||” for setting the default values. Thanks for sharing your solution 🙂

Collapse
ggenya132 profile image
Eugene Vedensky

That spicy proposal looks exciting. 'Elvis' operator is totally suited to javascript

Collapse
samanthaming profile image
Samantha Ming Author

Hahaha, I think I learned something new! Never knew that was called the ‘elvis’ operator 😂

Collapse
ggenya132 profile image
Eugene Vedensky

I first heard it referred to as that when I was reading through a groovy scripting tutorial!

Thread Thread
scheidig profile image
Albrecht Scheidig • Edited

The Elvis operator ?: returns left-hand side if it is trueish, right-hand side otherwise, thus comparable to object || default. groovy-lang.org/operators.html#_el...
It is called Elvis because it looks like an Elvis emoticon, but I always memoized it with "Not sure if he still exists" :-)

  king?:sing()

OTOH, the safe-navigation operator ?. will return left-hand side if it is null, otherwise evaluate right-hand side on the result of left-hand side, thus comparable to object && object.prop groovy-lang.org/operators.html#_sa...

So the proposal for JavaScript is not the Elvis operator, but comparable to the safe-navigation operator.

Thread Thread
samanthaming profile image
Samantha Ming Author

Indeed! Yes, thanks for the correction. In my new blog post, I talk about the Elvis Operator and hopefully others won't make the same confusion as I had 😅

Collapse
tdubs profile image
Thom W

I always felt using the && operator in this manner was an unintentional. And that its a quirk of JS. Like it should only be used in the if statement. Nevertheless it's super useful.

Collapse
samanthaming profile image
Samantha Ming Author

Definitely something to keep in your toolkit. Even if you don’t use it. If you ever come across that code, at least you will be able to follow what other people are trying to do 😊

Collapse
ancientswordrage profile image
AncientSwordRage • Edited

The issue comes when people chain up 5 at once and you get bogged down with the 4 or so properties before the one you're trying to get.

Much prefer lodashes has or object destructuring.

Collapse
motss profile image