knowledge machine

article > tech

How to protect your valuable variables from "undefined"

Prevent unexpected undefined assignments to JS variables

07/24/2020#javascript

JavaScript has a quirk where it assigns undefined to variables that have no value assigned to them. So if you access an object property via a key that isn’t part of the JavaScript object, it spits out undefined. Because it has something assigned to it, it doesn’t throw an error that you accessed it, it just goes away. When you actually do something with that property or variable, you get an error because you can’t do it with undefined. When I see an error on the console that says something is not a property of undefined, I feel like they should have told me that earlier,

JS Billon undefined

const zooObj = {
  cat: { age: 4, color: 'orange' },
  dog: { age: 7, color: 'black' },
};

console.log(animalsObj.elephant); //undefined - no error thrown

// If you try to do anything with it, it throws an error.
// TypeError: Cannot read property 'age' of undefined
console.log(animalsObj.elephant.age);

function getElephantAge() {
  return zooObj.elephant.age;
}

In a large app, this can happen repeatedly, and it can be quite a headache to have to keep track of whether undefined is assigned because the object doesn’t have any properties. If we could specify that if a value isn’t assigned, it’s not undefined, but some other arbitrary value, or even some other false value, we could prevent unexpected undefined assignments from breaking the flow of our code. In this post, I’ll outline a simple JavaScript syntax to prevent accidental undefined assignments to variables.

Of course, this is a problem that can be solved by using the static typing provided by Typescript, but this post is about how to prevent unexpected undefined assignments with a proposed or released JavaScript syntax only!

1. default parameter

const defaultZooObj = {
  cat: { age: 4, color: 'red' },
  dog: { age: 5, color: 'black' },
  elephant: { age: 34, color: 'green' },
};

function getElephantAge(zooObj = defaultZooObj) {
  return zooObj.elephant.age;
}

const elephantAge = getElephantAge(undefined); //34

You can use a function’s default parameter as a way to avoid having undefined parameters in a function. This syntax was added in ES6. The value you set as the default value is assigned not only when no parameters are assigned in the function, but also when undefined is assigned to a parameter.

In real-world apps, I don’t think you’d want to assign a large default value like the codeblock in the example. I think it’s too much of a typing disadvantage, and it’s better used to prevent undefined from being assigned to primitive types of parameters rather than complex parameters like nested objects.

function addAge(elephantAge = 34, myAge = 25) {
  return elephantAge + myAge;
}

addAge(undefined, 20); // 54
addAge(45, undefined); // 70

2. double negation

const elephantAge = !!zooObj.elephant.age; // false not undefined

The !! is a type of logical operator that has existed in JavaScript for a long time. It forces any type of value to be converted to a boolean value and becomes true or false depending on whether the value is true or false. If the value of elephant is undefined due to some side-effect, accessing elephant through this operator will give you a value of false - removing the undefined! This is the syntax recommended by the Airbnb JavaScript Style Guide as an alternative to the potentially unnecessary ternary operator. They say it’s good to remember something like this: bang(!) bang(!) you`re boolean.

3. optional chaining

const elephantAge = zooObj.elephant?.age; //undefined

Note that this syntax for chaining with ? It's in [tc39 proposal stage 4](https://github.com/tc39/proposal-optional-chaining/), so it's very likely to be released soon. This syntax doesn't prevent assigning undefined per se, but rather prevents errors caused by referencing undefined as the key to a property (i.e., by using .). Accessing undefined with .` does not raise an error, but instead spits out undefined.

Personally, I think this is the most useful syntax introduced in this post. The undefined type error that occurs in real-world app builds is when some property inside an object is unexpectedly undefined. This is where optional chaining comes in handy, because it allows you to know if a property exists without writing a conditional statement to evaluate it, without throwing an error.

4. nullish coalescing operator

// assigns 0 instead of undefined.
const elephantAge = zooObj.elephant ?? 0;

// Roughly the same as above
if (zooObj.elephant) {
  return true;
} else {
  return false;
}

// works well with optinal chaining.
const elephantAge = zooObj.elephant?.age ?? 0;

The ??, null merge operator automatically assigns the value on the right side of the operator if the value on the left side of the operator is false. This grammar is also in stage 4 of the TC39 proposal. It feels like a completely concise conditional statement, which is great for making your code more readable, and if you need to evaluate whether some property of an object is true or false, you can simply use it in conjunction with optional chaining.

Conclusion

We’ve seen some JavaScript syntaxes that protect valuable variables from the threat of undefined assignments. Some of them, like optional chaining and the nullish coalescing operator, have been applied in projects at my company, and I didn’t know about them until now. It made me realize that I need to be a developer who is more sensitive to the latest trends. I think it would be good to have the ability to consider adopting the latest syntaxes from tc39 or ES released every year for robust code. I also need to learn more about transpilers like babel so that my project can support the latest syntaxes seamlessly.

The following links are to babel polyfills for introducing optional chaining or nullish coalescing operator into your project. Take note if you’re considering introducing either grammar into your project!

Written by Jonghyuk Max KimSend emailCopy linkShare on X
← Back to all postsPreviousNextRandom