The Trouble with Nesting Ternaries in JavaScript

For years, developers have argued over the most readable way to nest ternaries. The ternary conditional operator is an alternative to if/else statements that make decisions based on a condition. Because the conditional operator is an expression that returns its result, it is tempting to nest further expressions within the branches.

Recently, popular JavaScript formatting solution Prettier released a new way to format these nested ternaries under an experimental flag, and that solution is gaining traction.

However, the reality is that ternaries shouldn’t be nested at all. Better options exist that not only get the job done but also do so in a way that prioritizes clean code: code that is consistent, intentional, adaptable and responsible. All developers write code with that goal in mind (or, at least, they should).

So, why is nesting ternaries such an issue? And what can developers do to eliminate the practice and make sure the code being written adheres to the principles of clean code as closely as possible to produce high-quality software? Let’s dig in.

Nested Ternaries Complicate Code

Don’t get me wrong, Prettier is a very important tool for the JavaScript ecosystem, helping us write consistently formatted code, which fits in well with the tenet of consistency: one of the four properties of clean code that all developers should strive to write.

But hundreds of comments surrounding Prettier’s formatting of nested ternaries make it clear that there will never be consensus on how best to use nested ternaries. Here’s the solution: Eliminate them completely.

Nested ternaries only serve to muddle code, and they work directly against another property of clean code: Code should be clear and straightforward. Nested ternaries rarely are either of those things and in fact require coders to pick their way through question marks and colons to determine the meaning of an expression. Conversely, if/else statements spell out the meaning much more clearly.

I’m not alone in this thought. For example, SonarQube, SonarCloud and SonarLint all enforce the rule that ternary operators should not be nested as part of the Sonar way profile, to enforce quality and clarity of code.

So, what should developers do instead?

Better Options Exist

First, let’s look at an example of Prettier’s nested ternaries:

The easiest way to replace a nested ternary here is to turn it into a conditional. To do that, you need to set up a variable to assign within the conditional statement. Start the variable with its default value to save one else clause. Then apply the same logic as in the original example but with if/else blocks. It’ll look like this:

Some developers argue against this style because of its use of the let variable. Here, a ternary operator does have the benefit of being an expression — so it returns a value, while if/then statements don’t return anything, meaning that you have to mutate a variable or use return.

If that doesn’t feel right, you can refactor the statement into its own function and use early returns instead. Doing that means you can independently test the functionality so you can make sure it’s correct and can’t unintentionally break. As a bonus, you can also drop the extra variable assignment.

Now we’ve removed the ternaries, but the nesting remains. Regardless of the syntax, the more you nest code, the more complex your code is to understand. The best thing to do is reduce the amount of nesting as much as you can. In this code example, we can now take our function and refactor out the nesting.

The act of removing ternary operators and refactoring the nesting has led to code that is shorter, more testable and ultimately clearer.

Why Nest Ternaries at All?

With clarity in mind, it’s easy to wonder why developers write nested ternaries in the first place. Some experts point out the difference between statements and expressions, noting that expressions encourage us to avoid side effects and mutation. This can be done through “chained ternaries,” on which you perform operations on the conditions to ensure you can only ever chain in the else clause of the ternary.

Here’s their point: Using an if/else statement in place of an expression means you need to write code that causes side effects. But if you reduce a conditional to code that you can write as a nested ternary, you can then avoid those side effects and mutation by rewriting it as a function with returns, as we did above. But since there is nothing stopping you from writing mutations and side effects within a ternary, the argument comes across as pointless.

These developers in the camp of nested ternaries also argue that the syntax of an if/else statement creates clutter and takes up memory, causing interference and leaving more room for bugs. Exchanging ifs and elses for question marks and colons certainly still leaves room for bugs, too. Even if nested ternaries use fewer characters than the alternative, they can still create confusion and a lack of clarity within the code that if/else statements prevent. For many developers, having to translate ternary syntax actually makes it more difficult to catch bugs during maintenance than using more verbose code.

Some of this may come down to personal preference and the way each developer thinks. Further, users of JSX know that you cannot directly use if/else statements within JSX. This necessitates the use of ternary operators to make decisions, which leads to nesting when you are both conditionally rendering components and including conditional attributes.

In the end, it’s still in a developer’s best interest to minimize nested ternaries whenever possible in order to write the most clear, readable and consistent code possible.

Clarity over Brevity

The problem with nesting is the complexity it innately introduces to code where we should always look for simplicity and clarity. When you see a nested ternary, the first thing you need to do is to refactor the nesting as much as you can, and then use the patterns I mentioned to remove the nested ternaries altogether.

It’s true that the alternatives use more characters and require a developer to type more, but they create a much better, more easily read end product. Since we read code more often than we write it, it’s especially important to keep that experience in mind during the coding process.

Don’t listen to the hype that calls these if/else statements “ugly” — the look doesn’t matter nearly as much as a clear, readable result that’s easier for everyone to understand and change over time, whether the original developer is doing the modifications or not. Writing code that’s readable and understandable for the maximum number of developers is, after all, the key to creating high-quality software that will benefit a business for years to come.

Group Created with Sketch.

 

 

 

 

Top