I code using const (and why you should too)

The main benefit of using const vs let is signaling intent.

There have been endless tweets and many blog posts (even this ridiculous expletive-laden rant) about how const really isn't constant or how "It's just compiled down to let by Babel anyway, so why use it?"

I'm here to tell you why I ignore all of this "sound advice" and rely on const as an indication of code quality.

Myth: const isn't constant

The fact is you can never re-assign a const. The value that's assigned to it will remain that value until the variable loses scope and is destroyed ('til death do us part?)

Let's take a look.

const myCar = carA;
myCar = carB;

VM101:1 Uncaught TypeError: Assignment to constant variable.

In the example above, you see that you can not, re-assign myCar. If you do, you get an exception.

Selectively assign a value to a const

Hold on. If a const is, um… constant, then how in the world can you selective assign it a value?

Let's look at some code that sets a variable based on some user preference.

let myCar;
if (perferSportsCar) {
  myCar = sportsCar;
} else {
  myCar = minivan;

The code above is something that you might find in many a source code repo today. Some people point to this as a valid use case for using let over const. I see it as "code smell". It's verbose, repetitive, and adds visual clutter.

Let's try it again using a const instead.

VM101:1 Uncaught TypeError: Assignment to constant variable.

Yeah, we all should have seen that coming.

How then can we use a const and what was all that talk about code smell?

When I see a let, it tells me that maybe there is a better way to express what you are trying to accomplish. Let's refactor the code to allow for a const.

const myCar = perferSportsCar ? sportsCar : minivan;

Here we decide on a value using a ternary and then assign it. The value of myCar is never re-assigned, but its initial value is selectively determined.

What if we can't use a simple ternary?

There are times when a simple ternary won't cut it. Take this common scenario.

let myCar;
if (type === 'sportscar') {
  myCar = sportsCar;
} else if (type === 'minivan') {
  myCar = minivan;
} else if (type === 'suv') {
  myCar = suv;
} else if (type === 'luxury') {
  myCar = luxury;
} else {
  myCar = economy;

Based on type we assign myCar to one of four different cars and default to economy if it's not one of the tested conditions.

When I'm doing a code review and something like this and see that let, it's a red flag. 🚩

Here's something a little more maintainable.

const cars = { sportscar, minivan, suv, luxury };
const myCar = cars[type] || economy;

Or even using Set.

const cars = new Set([sportscar, minivan, suv, luxury]);
const myCar = cars.get(type) ?? economy;

What do you know, it can be expressed using a const (but you knew I was going to say that, didn't you?)

Are there exceptions to this? Certainly. Just the other day I wrote some code that set the value of a let based on a range of numeric values. This would have been more difficult, and make the code less maintainable if I had used a const.

If const is constant, then why can I change its value?

If your const contains an array or an object, yes, you can change its properties, but the value remains constant. Take this example.

const sportsCar = new Car({ type: 'sportscar' });
const myCar = sportsCar;

myCar === sportsCar; // true

myCar.color = 'red';
myCar === sportsCar; // true

Notice that we've changed (i.e. mutated) myCar by setting the color property to "red", yet its value (i.e. sportsCar) remains the same.

Think of it like this. If I buy a car and then paint it red. Is it the same car? Yes. What if I install some sweet new rims? It's still the same car. Starting to get the picture?

Simply changing some aspect of my car doesn't make it a different car, just like setting myCar.color='red' doesn't change the value myCar.

Note: There are ways to freeze an object, which prevents mutation, but that's a different story.

In conclusion

Show me a project coded using all const and I'll show you one that is in all likelihood well written.

For me, const vs. let is less about re-assignment and more about what it says about your code. If your code can be written with all const then I get a better feeling that nothing fishy 🐠 is going on. And when I see that one let, it tells me that I need to examine what's going on a little further.

So let (pun intended) Babel changes my const's to let's a transpile time. As many proponents of let are quick to point out, we save one character per instance in our bundle size! 💃