Some months ago I was on Hacker News (as one does) and I ran across a (now deleted) article about not using if
statements. If you’re new to this idea (like I was), you’re in a for a real treat. Just search for “if statements” on Hacker News. You’ll get articles proposing that you might not need them, articles that refer to them as a code smell and even the quintessential “considered harmful.” Listen, you know a programming concept is legit when people start suggesting that using it is actually gonna hurt somebody.

And if that’s not enough for you, there is always the “Anti-If Campaign.” If you join, you get a nifty banner and your name on the website. IF you join. Oh the sweet, sweet irony.
The first time that I ran across this bizarre “if anathema” phenomenon, I thought it was interesting, but probably just more people mad on the internet. You are always one Google search away from finding someone who is mad about anything. Like this person who hates kittens. KITTENS.
Some time later, I was watching Linus Torvald’s TED interview. In that interview, he shows two slides. The first slide contains code that he deems is “bad taste.”

And the second is that same code, but in what Linus would consider, “good taste.”

I realize that Linus is a bit of a polarizing figure, and you might not agree with the “good taste” vs. “bad taste” phrasing. But I think we can universally agree that the second slide is just easier on the old eye balls. It’s concise, has fewer logical paths to follow, and contains no if
statement. I want my code to look like that. It doesn’t have to be some genius algorithm (it never will be), but I think it can be clean, and remember what Billy Corgan of Smashing Pumpkins said about cleanliness…
Cleanliness is godliness. And god is empty. Just like me.
– Billy Corgan, “Zero”
So dark! But what an amazing album.
Aside from making your code look cluttered, if
statements, or “branching logic,” requires your brain to hold and evaluate two separate paths at one time along with all of the things that might occur on those paths. If you nest if
statements, the problem intensifies because you are creating and tracking a decision tree and your brain has to bounce around all over that tree like a drunk monkey. This kind of thing is what makes code hard to read. And remember, you should write your code thinking of the moron who comes after you that is going to have to maintain it. And that moron is probably you.
As my own favorite moron, I’ve been making a conscious effort lately to avoid writing if
statements in my JavaScript. I don’t always succeed, but what I’ve noticed is that at the very least, it forces me to think about solving the problem from an entirely different angle. It makes me a better developer because it compels me to engage a part of my brain that is otherwise sitting on a beanbag eating peanut M&M’s while the if
statement does all the work.
In the process of not writing if
statements, I’ve discovered my love for the way JavaScript lets you compose conditional logic with ternary statements and logical operators. What I would like to propose to you now is that ternary has gotten a bad rap, and you can use it along with the &&
and ||
operators to write some pretty concise and readable code.
The much maligned ternary
When I first started as a programmer, people used to say, “Never use a ternary. They are too complex.” So I didn’t use them. Ever. I never used a ternary. I never even bothered to question whether or not those people were right.
I don’t think they were.
Ternaries are just one-line if
statements. Suggesting that they are implicitly too complicated in any form is just… not true. I mean, I’m not the frostiest donut in the box, but I have no problems at all understanding a simple ternary. Is it possible that we are infantilizing ourselves here just a tad when we say to always avoid them. I think that a well-structured ternary beats an if
statement every time.
Let’s take a simple example. Say we have an application where we want to test and see if the user is logged in. If they are, we send them to their profile page. Otherwise, we send them to the home page. Here is the standard if
statement to do that…
if (isLogggedIn) {
navigateTo('profile');
}
else {
navigateTo('unauthorized');
}
That’s a damn simple operation to split out over six lines. SIX LINES. Remember that every time you move through a line of code, you have to remember the code that came above it and how it affects the code below it.
Now the ternary version…
isLoggedIn ? navigateTo('profile') : navigateTo('unauthorized');
Your brain only has to evaluate one line here, not six. You don’t have to move between lines, remembering what was on the line before.
One of the drawbacks to the ternary, though, is that you cannot evaluate for only one condition. Working from the previous example, if you wanted to navigate to the profile page if the user was logged in, but take no action at all if they weren’t, this won’t work…
// !! Doesn't Compile !!
logggedIn ? navigateTo('profile')
You would have to write out an actual if
statement here. Or would you?
There is a trick that you can use in JavaScript when you only want to evaluate one side of the condition and you don’t want to use an if
statement. You do this by leveraging the way JavaScript works with the ||
(or) and &&
(and) operators.
loggedIn && navigateTo('profile');
How does that work!?
What we’re doing here is asking JavaScript, “Are both of these things true?” If the first item is false, there is no reason for the JavaScript virtual machine to execute the second. We already know that both of them aren’t true because one of them is false. We’re exploiting the fact that JavaScript won’t bother to evaluate the second item if the first one is false. This is the equivalent of saying, “If the first condition is true, execute the second.”
Now what if we wanted to flip this around? What if we wanted to navigate to the profile page only if the user is not logged in? You could just slap a !
in front of the loggedIn
variable, but there is another way.
loggedIn || navigateTo('profile');
What this says is, “Are either of these things true?” If the first one is false, it has to evaluate the second to know for sure. If the first one is true though, it will never execute the second because it already knows that one of them is true; therefore the whole statement is true.
Now, is that better than just doing this?
if (!loggedIn) navigateTo('profile');
No. In that form, it is not. But here’s the thing: once you know that you can use the &&
and ||
operators to evaluate equality outside of if
statements, you can use them to vastly simplify your code.
Here is a more complex example. Say we have a login function where we pass a user object. That object may be null, so we need to check local storage to see if the user has a saved session there. If they do, and they are an admin user, then we direct them to a dashboard. Otherwise, we send them to a page that tells them they are unauthorized. Here is what that looks like as a straight-up if
statement.
function login(user) {
if (!user) {
user = getFromLocalStorage('user');
}
if (user) {
if (user.loggedIn && user.isAdmin) {
navigateTo('dashboard');
}
else {
navigateTo('unauthorized');
}
}
else {
navigateTo('unauthorized');
}
}
Ouch. This is complicated because we’re doing a lot of null condition checking on the user
object. I don’t want this post to be too strawman-y, so let’s simplify this down since there is a lot of redundant code here that we would likely refactor into other functions.
function checkUser(user) {
if (!user) {
user = getFromLocalStorage('user');
}
return user;
}
function checkAdmin(user) {
if (user.isLoggedIn && user.isAdmin) {
navigateTo('dashboard');
}
else {
navigateTo('unauthorized');
}
}
function login(user) {
if (checkUser(user)) {
checkAdmin(user);
}
else {
navigateTo('unauthorized');
}
}
The main login function is simpler, but that’s actually more code and not necessarily “cleaner” when you consider the whole and not just the login
function.
I would like to propose that we can do all of this in two lines if we forgo the if
statements, embrace the ternary, and use logical operators to determine equality.
function login(user) {
user = user || getFromLocalStorage('user');
user && (user.loggedIn && user.isAdmin) ? navigateTo('dashboard') : navigateTo('unauthorized')
}
That’s it. All of that noise generated by if
statements collapses down into two lines. If the second line feels a bit long and unreadable to you, wrap it so that the conditions are on their own line.
function login(user) {
user = user || getFromLocalStorage("user");
user && (user.loggedIn && user.isAdmin)
? navigateTo("dashboard")
: navigateTo("unauthorized");
}
If you are worried that maybe the next person won’t know about how the &&
and ||
operators work in JavaScript, add some comments, a little white space and a happy tree. Unleash your inner Bob Ross.
function login(user) {
// if the user is null, check local storage to
// see if there is a saved user object there
user = user || getFromLocalStorage("user");
// Make sure the user is not null, and is also
// both logged in and an admin. Otherwise, DENIED. 🌲
user && (user.loggedIn && user.isAdmin)
? navigateTo("dashboard")
: navigateTo("unauthorized");
}
Other things you can do
While we’re at it, here are some other tricks you can play with JavaScript conditionals.
Assignment
One of my favorite tricks (which I used above), is a one-liner to check if an item is null and then reassign it if it is. You do this with an ||
operator.
user = user || getFromLocalStorage('user');
And you can go on forever like this…
user = user || getFromLocalStorage('user') || await getFromDatabase('user') || new User();
This also works with the ternary…
user = user ? getFromLocalStorage('user') : new User();
Multiple conditions
You can provide multiple conditions to a ternary. For instance, if we want to log that the user has logged in and then navigate, we can do that without needing to abstract all of that into another function. Wrap it in some parentheses and provide a comma.
isLoggedIn ? (log('Logged In'), navigateTo('dashboard')) : navigateTo('unauthorized');
This also works with your &&
and ||
operators…
isLoggedIn && (log('Logged In'), navigateTo('dashboard'));
Nesting ternary expressions
You can nest your ternary expressions. In his excellent article on the ternary, Eric Elliot demonstrates that with the following example…
const withTernary = ({
conditionA, conditionB
}) => (
(!conditionA)
? valueC
: (conditionB)
? valueA
: valueB
);
The most interesting thing Eric is doing there is negating the first condition so that you don’t end up with the question marks and colons together, which makes it harder to read. I would take this a step further and add a little indentation. I also added the curly braces and an explicit return because seeing one parenthesis and then immediately another makes my brain start to anticipate a function invocation that is never coming.
const withTernary = ({ conditionA, conditionB }) => {
return (
(!conditionA)
? valueC
: (conditionB)
? valueA
: valueB
)
}
As a general rule, I think that you should consider not nesting ternaries or if
statements. Any of the above articles on Hacker News will shame you into the same conclusion. Although I’m not here to shame you, only to suggest that perhaps (and just maybe) you will thank yourself later if you don’t.
That’s my pitch on the misunderstood ternary and logical operators. I think that they help you write clean, readable code and avoid if
statements entirely. Now if only we could get Linus Torvalds to sign off on all this as being “good taste.” I could retire early and and live the rest of my life in peace.
One thing I love about ternaries is that they’re expressions rather than statements, and as such they can apply to only part of an instruction. So the first example can be further simplified as
navigateTo(isLoggedIn ? 'profile' : 'unauthorized')
.WHOA! That’s freaking amazing! I did not know that you could do that.
Noki Doki: Thank you! I was thinking the same thing!
Ternary operator is an OPERATOR, not a control statement! It should be used to select a value, not an action!
Use cases:
1. Perform the same action, but with different values (Noki Doki’s example)
2. Intialize a variable, especially a constant (Christopher Kirk-Nielsen’s example)
Yeah, that is actually the better way of writing that line, IMO.
In fact some style guides / linting rule sets forbid standalone ternary expressions that aren’t either part of a statement or assignment.
I love ternaries for variable assignment such as
var togglerIsOpen = el.hasAttribute('open') ? true : false
(dumb example that doesn’t even need the ternary but you get the point). I’ve also written nested ternaries like in your last example. I strictly use it for short variable assignments while trying to respect immutability. As long as it’s not too complex, I’m all for it.Where I disagree with your post is the “shorter code is easier” approach, like this one
isLoggedIn && (log('Logged In'), navigateTo('dashboard'));
. That is not easy to read, and someone who isn’t used to the short-circuiting feature would very easily get lost (I know I would). A conditional block is maybe longer but to me it’s so, so much easier to read, break apart, and digest. You have a clear view of what happens and why, everyone can read it, and you can add conditions/operations without wondering if the whole thing will still work.I think it’s great to know about ways to shorten code that still works the same, but I let minifiers worry about that. I could see this being super useful for code-golf, though!
I guess that, as always, it boils down to personal preference. Still glad to have learned a couple of things from this post, so thank you! :)
PS: In the Assignments section about
||
(which I also love using!), the ternary doesn’t yield the same result as the||
line above. I believe it should beuser = user ? user : getFromLocalStorage('user') ? getFromLocalStorage('user') : new User();
right? — not as succinct, though.Great catch! Thank you.
I agree with this, in the sense that more concise code is not the same as better code. I’ve had more success in making code readable by exiting early where necessary.
That being said, I am a big fan of using ternary to set initial values as per the examples.
Biggest takeaway? Always question and use the right tool for the job. If’s have their place and so do ternaries.
Just found this article and I noticed you still haven’t fixed that line
user = user ? getFromLocalStorage('user') : new User();
which made me pause for a whole minute when I saw it.As long as we’re doubling the calls for the sake of using only ternaries, the full conversion would be
user = user ? user : getFromLocalStorage('user') ? getFromLocalStorage('user') : await getFromDatabase('user') ? await getFromDatabase('user') : new User();
amiright?In your isLoggedIn example, I’d much prefer to use the ternary to assign a destination, then do the navigation, as it separates out the action from the logic that decides the conditions around the action. Thus:
Either is vastly preferable to the
if... else...
construct, of course. Thanks for the article!I’m a ternary fan, so agree with all of this. Less code is better.
One thing to be aware of is in the check for null:
jim = jim || “default value”
This is something to avoid if jim could be a number or boolean (I think). Or anything which might be valid but falsey.
Right, that catches all 7 falsey values in JS: null, undefined, false, +0, -0, NaN and the empty string
Good point! Although the one issue I have with type problems is that I just never encounter them. They seem to be more hypothetical than real-world. This is my primary hang-up with typed languages. To me it feels a bit like being a prepper.
Interesting read. I don’t agree with the point, though. My arguments:
As mentioned in a previous comment, shorther code !== more readable code.
Just because you can do something doesn’t mean you should do it all the time, or that it’s a good idea. That example where the comma expressions are used is IMHO just malicious advice.
You can seldom say some way of coding is always better than another. Most of the time, you have to make a decision between multiple options, considering the trade-offs of each option for that specific scenario. And, I think, the case of ternary expressions vs if statements is just a good example of this.
Lastly, IMHO, this code:
is, by all means, easier to read and follow than this one:
Yes – it’s easier to read on it’s own. If you have a file full of these, it’s not so much fun to look at.
I don’t disagree with this last point here. The first block is easier to read. The problem is that it requires the other blocks to function, so to understand the full logic and all possible side-effects, you have to change context and handle the branching logic. For me, that’s harder than having everything right in front of me.
Agreed, although I would make one change to your example. I find it’s better to check for positive things, rather than negative.
That also has the benefit of failing by default, which will protect you from a bug that might allow access when it shouldn’t have.
Thank you, Brad! I like that better too.
@Brad, When you switched to “positive” checks, you forgot to switch the || back to &&:
I’ve learned that the ternary is a good choice when the statement fits into one line (less than 81 characters) and used it accordingly.
So does that mean all this anti-if noise I noticed in the recent past is really just about style, but not about avoiding ‘if’ in a logical sense? WTF? Feels like back and forth fashion talk.
I think it’s all hot takes really. You can consider this article yet another hot take.
Just because you can doesn’t mean you should. There are times where ternaries are great, but outside of very simple cases like variable assignment they make code a lot less readable very fast. Code readability, for yourself, for colleagues, for other users of your code, is infinitely more important than feeling smart because you wrote something terse and cool-looking.
I agree that big if statements and lots of diverging paths can be unpleasant to look at, but that’s the point at which you step back and think more carefully about the logical paths in your code, not go whole hog on something more confusing because it’s more immediately aesthetically pleasing.
Very true.
I suppose it’s like a pendulum. Somewhere in the middle, there is a balance. For some reason, we like to swing drastically to one side or the other.
Gr8 article. Only one thing:
The right code for withTernary (that worked for me) is:
Also assignment
…
x && (y=2);
Be aware, and I can’t stress it enough, to NOT use logical operators like that if falsy values are valid ones
If
if
statements are to be discouraged, we should be moving towards more logical and advanced programming constructs, not packaging old wine in new bottles.This is right! You are right. A ternary is not a replacement for a conditional because it is one.
The
if
shamers are gonna come for me! Tell my wife and kids that I love them.“You can provide multiple conditions to a ternary.” I had no idea this was possible. My default has always been to move it to an if statement if the ternary needed to do more than one thing. The parentheses and comma is a game-changer. Great tip and great article, thank you!
Nice! Truth be told, I didn’t know that either until I started doing research for this article.
I find nested ternaries easier to read if you style them like
if
statements:I agree with all you’ve said about ternaries, but don’t like using expression evaluation just for the side effects. So:
Prefer:
Don’t like:
The 2nd example is an expression, which should be pure, and not cause side effects.
Statements, like standalone function calls or assignments, are executed for their effects.
Thanks for the article! It’s a great read! Since in the above examples, we have only used objects and functions. It would be great if we also throw some light on abstracting conditions in arrays using handy methods like
Array.prototype.some()
andArray.prototype.every()
and use ternaries within them. It would be a great addition to this article! :)Do these awesome tricks only work with JS?
I really enjoyed reading this article.
I think the code looks clean and elegant.
It is very important to read the comments otherwise you miss the contributions of Noki Doki and Kirk-Nielsen as summarized by Matt Seitz in two major conclusions.
So it would be great if the article is updated including the suggested improvements, and giving credit for their contributions.
Thank you all.
I would like to point out that || does not check if an item is null. Instead, it checks if an item is truthy. This is a very important detail to keep in mind:
var item = 0;
item = item || 1;
console.log(item); // -> 1
“One of the drawbacks to the ternary, though, is that you cannot evaluate for only one condition.”
which could be just:
logggedIn ? navigateTo(‘profile’) : null;
That is definitely less desirable than simply writing
if (loggedIn) navigateTo('profile')
It is avoiding the
if
statement just for the sake of it, and replacing it with what is, in effect, an alternative and less explicit syntax for theif....else
construct, and there’s no point usingif...else
if you don’t need theelse
part.Furthermore, it is using an expression as a statement, which you shouldn’t do. Using the ternary operator creates an expression that evaluates to a value, not a statement, and you would never just write a value without assigning it to a variable or passing it to a function call.
So you should either do this:
navigateTo(loggedIn ? 'profile' : 'login')
or this:
const redirect = loggedIn ? 'profile' : 'login'
Anytime I see someone knock ternaries and complain about how they are allegedly so hard to read, it tells me that that individual probably doesn’t have a good grasp of javascript. Akin to using classes instead of learning factory functions and composition. I use ternaries all the time, whenever I can. Here’s my tip for those of you who have a hard time reading ternaries: SPEAK THEM OUT LOUD. Example: “Is user logged in? If so, take them to the dashboard, ELSE, take them some where else” ( logged_id ? dashboard() : logInPage() )
This is a fantastic read. Thank you for putting this out to the community. Using functional code best practices by creating smaller and more concise code has been a common theme in bug free code in my experience. Fantastic!
This ternary expression in the article:
isLoggedIn ? navigateTo('profile') : navigateTo('unauthorized');
is even better like this:
navigateTo(isLoggedIn ? ‘profile’ : ‘unauthorized’);
I think it’s better because it makes it very clear that you’re going to
navigateTo
and the only question is where.You can actually avoid the user = user || getFromLocalStorage(“user”) with ES6’s default function parameters, thus further improving readability and reducing code length:
function login(user = getFromLocalStorage(“user”)) {
….
}
Hey Burke, interesting topic!
I just want to point out that “good taste” is highly opinionated, and so are some parts of your writeup.
As you already stated, I also think that the main concern when writing a piece of code is to make it readable. And while there isn’t a single best way to make it so, there are, unfortunately, many many “less good” ways to improve readability… and one of them I think is the ternary operator
I personally use the ternary operator quite often, but as others already stated in the comments, it’s not intended to be used as an
if
replacement. I use it for variable assignment, and that’s it.You can write your code as “smart” as you can and tidy all the expressions in 2 lines, but it won’t help you the next time you read it… it will actually give you a headache as you have to rethink your code as you read it.
All I want to say is that you can write perfectly readable code using
if
statements, and probably a lot cleaner than using lots of inline expressions. For example, I would rewrite your first function that’s bloated with 4if
s (that are also nested) like this:And once you’ve separated the variable assignment from the actual function calls, you can easily swap that if with a ternary operator if that’s your thing:
Seems pretty similar to your ternary rewrite, no?
I don’t think there should be a war between
if
statements andternary
operators… you can write shitty code with both of them. You just need to take care to use all the tools you have (like naming and spacing) to dumb down the code and make it readable and easy to maintain (even it means that your function will be spawned cross multiple lines).Also it’s worth mentioning that from a testing perspective, if statements seem easier to test
Keep up the good work and overall nice article! ✌️
I wouldn’t call it a trick, more a technique, namely short circuit [boolean] evaluation. Javascript programmers are lucky enough to be able to use it.
see https://en.wikipedia.org/wiki/Short-circuit_evaluation
I love ternary operators too :)
Didn’t know about the
&&
and||
tricks so mind was blown there. Then blown again when I read Noki Doki’s comment aboutnavigateTo(isLoggedIn ? 'profile' : 'unauthorized')
:)Since we’re trying hard to reduce complexity and improving readability, I feel duty-bound to pedantically point out that in the following statement, the parentheses are completely unnecessary since the logical operators are the same:
Of course, if it looked like this then they would be required:
And since I’m being pedantic, I should also point out that I made a mistake referring to that as a statement – it’s an expression!