Cover image for If/else or just if?

If/else or just if?

tyrw profile image Tyler Warnock ・1 min read

Today in a code review we had a statement like this:

Statement A

if (typeof val === 'string') {
    return 'A'
} else if (val === null || val === undefined) {
    return 'B'
} else {
    return val

And a suggestion was made to switch to the following:

Statement B

if (typeof val === 'string') return 'A'
if (val === null || val === undefined) return 'B'
return val

I won't tell you where we came out 😜, but which do you feel is a better way?

Was the suggestion to be concise and avoid if/else logic a good one, or was the original way better?


markdown guide

I prefer the second syntax because it acts like a "guard" against further execution, so to speak. The first syntax just encourages more nesting and levels of indentations. To me, it is more readable to have a "guard" condition than to have if-else blocks.


I call it the Short-circuit or (Fast-fail)[en.m.wikipedia.org/wiki/Fail-fast]. It will help you just worry about less things if it's not followed by else


I have the same train of thought with it! A senior developer at a previous job introduced it to me


The first time I heard the term "guard" was in haskell. Is it any related?


I'm quite surprised actually. Given the imperative nature of if statements, I wouldn't expect Haskell (of all languages) to be the origin of that term.

Haskell (among other functional languages, I guess) has guards for pattern matching

sign x |  x >  0        =   1
       |  x == 0        =   0
       |  x <  0        =  -1

I always go with Statement B. This is known as "early returns" and helps with confusing success/error cases. Take for example:

function createPost(post) {
  // Earliest potential error if no post is provided.
  if (!post) return false;

  // Ensure correct data type.
  if (typeof post !== 'object') return false;

  // Ensure required data is provided.
  if (!post.title || !post.body) return false;

  // We're all good at this point. Assume it's safe to create the post!
  const isPostCreated = create(post);

  return isPostCreated;

It's nice to know for sure that the end of the function where we're saving the post to the database will not error out due to bad data, since we already verified those cases earlier.


I like this style more - it looks clearer to me, and from the point of working through the logic, I like that the returns just end the function.

If a block just set a value and returned it later, there's a chance it could be reassigned in another buggy block, so I think there's less risk in this style too.


This looks great to me. I'd be happy even without the comments as it feels pretty self-documenting.


I added the comments just for the sake of the example, but they should definitely be removed for a real app.


I prefer the first approach, it's ensures all cases are covered, and is more extensible IMO.

I also prefer a single return per function, excluding sometimes null / wrong validations, as this code tends to be easier to read and debug. In your example, I would use the first method, but assign the return value to a variable, and return it after the statements.

This made me thing of this post on hackernews: Please do not attempt to simplify this code

Kubernetes controller source

  1. Every 'if' statement has a matching 'else' (exception: simple error checks for a client API call)
  2. Things that may seem obvious are commented explicitly

We call this style 'space shuttle style'. Space shuttle style is meant to
ensure that every branch and condition is considered and accounted for -
the same way code is written at NASA for applications like the space


Can you elaborate on the "cases are covered" point? In my mind both snippets covered all cases, but I'm open to hearing otherwise.


In this case, both examples are the exact same of course.

This is somewhat related to a single return statement in a function, but the syntax of an if/else if/else is more explicit than the various conditions are related to each other.

With few if statements each statement is independent from the others (unless you return in the previous cases, like in your example), therefore more than one of them can be triggered.

Overall, while there aren't many arguments for any of these approach in your specific scenario, I feel like it's a better practice to have a single style of conditions for your whole codebase. As the first approach is more flexible, I strongly prefer using it everywhere!

Consistency is definitely most important. I just did a search through an API that I built recently, and I only have 3 else statements which I can probably refactor out. So, I think it's definitely possible to go all-in on early returns.


TIL about "space shuttle style", very interesting.

I'm not sure if the Kubernetes controller source is meant to be used as an example though. Otherwise there would be no comment to warn people from simplifying the code.


In other languages such as Scala and Rust there is a "match" statement and a compiler that looks at the types can tell you if all cases are matched. In Scala you can compose/chain together sets of partial methods that match a set of related cases and the compiler will tell you if the combination will do an exhaustive match. So what the Kubernetes example you post is pointing out is that the devs are having to work around a missing feature in the language they are using. Once you have used a language that has an exhaustive match you never want to go back. This is because it is very much easier to write code that you know won't just fall through to some wrong default case when someone adds a new type of input.


I don't prefer one over the other, but what I do prefer is a single return statement, so you can make more assumptions about the code (eg: should get to the end of the function if there's no error)

let result

if (typeof val === 'string') {
    result = 'A'
} else if (val === null || val === undefined) {
    result = 'B'
} else {
    result = val

return result

IMO, the single return comes from C coding guidelines where it may help developers easier to trace the complex code and prevent them from forgetting release any resources which need finalizing (like freeing heap). For this point, C++ projects usually don't adopt this guideline since it has its own stack-unwinding thing.

For Javascript, I prefer the statement B for more readable code. Save everyone's effort.


I find it more confusing to return a variable in a return unless it is really basic (like changing the message of a JSON response depending the data given).

Early returns make it sure you don't even up with mutating the response somewhere later in the code. It also make more readable (imo) because not everything is nested.


A lot of people would recommend using const by default. A variable that can be many things is cognitive overhead and results in bugs down the line.


I prefer B, if only because it is a one to one mapping of cases to output - when reading the function it says:

When function is called
If val is a string, then return 'A'
If val is null or undefined, then return 'B'
Return val otherwise

This is a much more human way of thinking about the possibilities. I don't tend to think in terms of if/else conditions in the real world and I don't feel like much business logic works that way either. Option B is also easier to extend - if later you need to add an "if val is a number, return val.toString" or the like, then that is easy and you can add it wherever it makes sense in your code.

Slightly unrelated, but I also really perfer this style to switch statements. They have a place, but most times they should probably be multiple if statements.


@wuz Well said, and I totally agree on the switch statements piece. I'm not sure I've ever been satisfied with the look/readability of a switch statement in JS!


I prefer the "return early" syntax. It puts a line in the code where if you pass it, you know some assertion holds. The code above doesn't really illustrate that, but for example:

if (flag1) {
// Anything that follows, regardless of if / else nesting
// I know that flag1 is false.

As opposed to:

if (flag1) {
} else {
  // some stuff
// Some more stuff. Is flag1 false?

In the second example, imagine some ugly nesting. For each block of code you need to think "am I in a level where I've tested flag1?"


@farble1670 so do you prefer a hybrid of first and second? Something like:

if (typeof val === 'string') {
    return 'A'
if (val === null || val === undefined) {
    return 'B'
return val

Another option (for those who favour expressions over statements) can be built out of JavaScript's ternary operator:

return (typeof val === 'string') ? 'A'
     : (val === null || val === undefined) ? 'B'
     : val

Quite a popular pattern.


Ternary operators are really nice for simple and small statements, but I definitely wouldn't recommend them for anything complex. Makes things to hard to read for me. The same could be said for other developers.


That's not easy to read at all in my opinion...


If we know the branches will have return, then B, plain if, aka early return is better.

We don't need to keep the context of whose else we are in anymore most of the time.

Even refactoring it is easier, both in terms of just editing the code and the resulting git diff.

However, if we don't have return...

let val
// ...
if (typeof val === 'string') {
    val = 'A'
} else if (val === null || val === undefined) {
    val = 'B'
} else {
    val = /* do something here lol */ val
// ...

...then there are two options for me.

1. Extract into function

function testVal(val){
  if (typeof val === 'string') return 'A'
  if (val == null) return 'B'
  return val
// elsewhere...
let val
// ...
val = testVal(val)
// ...

2. Use a conditional expression

let val
// ...
val =   
  typeof val === 'string'
  ? 'A'
  : val == null
    ? 'B'
    : val
// ...

It just depends on the complexity, relevance, and size

What's particularly good about both?
They end up only assigning val once, so after some further refactoring we may end up with the superior const binding!


Is early return at odds with functional programming?
Should we strive to use conditional expressions at every size?

No. Used correctly, return is just guards in a match expression. You could see it as advanced pattern matching that is missing from JS syntax.
(Early throw, on the other hand, is usually a hack we have to use for lack of static types.)


The second one. Every time. For the early returns reason mentioned earlier. Since you're doing a return, the else is an anti-pattern.

Also this thread terrifies me for all the code that exists out there and solidifies everything about xkcd.com/2030/


Totally! "else" at the end of an if/else chain is a trap awaiting someone changing the input then making a mistake in the if/else such that the new input falls into the old else that does the wrong thing. Scala has "match" and the compiler gives an error if you don't match everything that can come in. Putting in a wildcard match at the end, which is equivalent of a last 'else' in JS, reads as "okay I don't recognise this input so I am going to ignore it". That screams anti-pattern as being both inefficient and inexact.


I prefer Statement A since it is more familiar, more explicit, and groups the possible outcomes. Almost every programmer has seen and used option A. It doesn't require changing the structure to make an update, if something needs to be added before the return statements, it is easy and predictable.

The second statement seems like brevity for the sake of brevity to me. It is shorter, but I'd argue that it is not concise because it does not present the information clearly (at least to me). On Statement B, the formatting would trigger a red flag for me. I'd likely have to take a second or third look just to make sure I know what the intention of the code was. I don't like single line if-statements because all it takes is accidental reformatting without adding braces to cause issues that are easy to miss. Some will argue that their editor does this all for them so maintainability is not an issue, but when working on a team I don't think that is a safe assumption. I'm sure someone could also argue efficiency gains of option B (smaller JS file), but that seems like overkill for minimal gain.


I think the second example is muddying the water by combining the pattern (failing early) with a style choice (single-line, braceless ifs).

I prefer Statement B, or would if it was written like this:

if (typeof val === 'string') {
  return 'A';

if (val === null || val === undefined) {
  return 'B';

return val;

I like this because it reduces nesting and acts as a barrier to people over-complicating a function. I mean that if the function ends up having to re-use a negated form of one of the earlier conditions or have a separate set of nested ifs after the guard conditions, then it's a big smelly smell and should be moved to its own function instead.

Also, if you think about it in terms of human experience, it's how we work. If you're tending a patch of garden, you don't think about what category of flower you're looking at and cross-reference it in a book if it's obviously a weed.


Which ever route is the easiest to read(usually it's the second one) is the one I pick. Less code is more.

I've worked with both a lot, and I find the second one is often better for my cognitive load. If you need if/else/elseif perhaps to many things are going on at once.

It depends on what kind of logic is needed, and which one reduces the amount of code and improves the readability.


Wouldn't you put the null and undefined check first to have a quick return?

if (!val) return B;
return (typeof val === 'string') 
    ? A
    : val;

Of course, you could go back to the more explicit null and undefined check if you think you might get other falsy values that don't fall into that condition like 0, empty string, false, and NaN.

But to answer the question, I prefer just 'if' whenever possible.


First one. Brackets are consistent I feel and easier to assess. I've heard the argument about one return per function although then you're potentially creating a local variable to manage state. What's truly important is that your developers can effectively read it, after all the computer obviously doesn't care.


I use both in two different situations. I use the first form at the top of a function when I'm doing assertions about parameters. Think of it as poor man's type checking or contracts in languages that don't have them, e.g.,

def f(a, b):
    if not instanceof(a, int):
        raise ValueError('a must be an int')
    if a < 0:
        raise ValueError('a must be nonnegative')

I use the second form in the primary body of code unless I am forced to do otherwise. The lazy reason is that I write in both imperative and functional languages, and in functional languages all ifs must have an else statement, so by always having an else, I have one less thing to keep track of between languages.

The more philosophical reason is that using the else block makes it very clear what the branch is in the execution path. The precondition and postcondition for both branches should be the same and the effects required to bridge that gap are all confined to those blocks. I have come to value this kind of locality more and more over the years.


If you find yourself doing this often, check this out: pypi.org/project/icontract/


I reckon that it all depends on what is your target.

Return statements, of course, you can easily use approach 2 or ternary operation. However, if you do any operations on a particular block, rather than return, if-else if -else construction guarantees that if an expression is evaluated to true, other blocks would not be executed, hence -> save your precious runtime. Thus, it would be only visible on a high-demanding calculation blocks.


I wouldn't do sample B as written because of the lack of braces for the if, which I'd always add (as well as spreading it out over more lines).

With that change, though, it's something that I do wonder about myself from time to time. With the exact sample given (where the else is just another return statement), I would usually go with sample A because the if-else-chain (which has a known mental model for me) nicely describes what happens. However, when the "else" portion is much larger (i.e. it's the "real implementation" after the corner cases have been taken care of) I'd probably go with something like sample B because it limits the levels of indentation that don't add information.

Ultimately, though, I'm not entirely consistent in this.


definitely the just "if" boat here as much as possible, although I avoid single line and practice the bracket method.


@dechamp something like:

if (typeof val === 'string') {
    return 'A'
if (val === null || val === undefined) {
    return 'B'
return val



yup! that is the good stuff right there!

And based off your example I would do this...

check for no value first, save the code from type checking if it's not set.

if (!val) {
   return 'B';

if (typeof val === 'string') {
   return 'A';

return val;

What if val is 0 or false? 😉

You have a good point, but are you expecting your system to act like that? It's very rare you need to actually be checking for that, but if you do suspect it then definitely go for the finite checking.

But then again, I love using the "joi" package for my type checking.

Normally no, but in this case yes. It's a bare-bones project and the code is constructing a DB query from a set of known inputs, so null and undefined get treated as null, strings get quotes around them, and everything else is passed through.


As long as every branch returns then the 2nd version is fine with me.
(Although I'd still use brackets instead of guard clauses because of personal preference regarding readability)

It becomes a problem when the if does not return and gets more complex than a simple one liner.

if (env.DEBUG) {
    Logger.log(/* message */);
// Rest of logic here

would obviously be okay, but

let var1;
let var2;
let var3;

if (/* Some condition */) {
    // Many lines
    // of code
    // that affect 
    // the state of 
    // the variables

// Rest of logic
// working on the 
// variables unconditionally,
// here

return result;

would not be okay, because it makes it really hard to reason about the output of the function and the logical flow of your data can't be parsed at a glance.


Hello, I prefer the second one, because in the past when I was reviewing my peer's code I was faced with the first style a lot and it put toll in my mind to process the meaning.

But I used to like the first one because it puts my mind at ease when writing it, knowing the else part is covered explicitly. But some time after when I need to read it again, to be honest, its not a nice experience.


Thrice return feels like code smell to me. :) Just kidding

But one can avoid redundant returns easily, as already mentioned.
Still, in such simple case the bulletproof method might be this one:

test = val =>
  typeof val === 'string' ? 'A' : 
  val === null || val === undefined ? 'B' : 

As you can see, the one line create one expression. In this case, it is guaranteed you don't miss anything.

Thankfully, there is no problem in chaining ternary operator in javascript like this. This is not the case in PHP, if someone was masochist enough to test it there :)


For easier readable, I prefer Statement B.
You know? This remind me the break statement comes after a return in switch...case. For such the case, I support break should come after finish every case branch. Just for safe 🙂


There isn't much value in the else since the first conditional results in a return, however having it aids in readability in this case by grouping these two similar conditions. but having a final return outside of a condition is a best practice to ensure you don't mistakenly return undefined. The trailing else should be removed if it is just a return statement.

function (value) {
  if (typeof(value) === 'string') {
    return 'A';
  } else if (value === null || value === undefined) {
    return 'B';
  return value;

Though in many cases, a map works better than a bunch of if/else's.

function (state) {
  const states = {
    indiana: 24,
    ohio: 36,
    florida: 19

  return states[state] || 0;

Using the mapped approach eliminates any need for switch statements.

Also, don't abbreviate your code, there is no benefit gained from shaving off a few characters. Let the uglifier worry about that. Your goal should always be readability above all else until something is noticeably slow.


It depends on the case, but I would probably pick a mixed case like this:

if (typeof val === 'string') {
return 'A';
if (!val) {
return 'B';
return val;

The main reason is because blocks are in my opinion better to see and less confusing. I also try to avoid the tenary operator, but it really depends on the case. Sometimes it's just perfect. There is no need to write an else in this case. The else if wouldn't improve any performance, and for me it's better to have no else case at all.


This is a classic versus modern debate.
Classics are classics because they stood the test of time, in which case statement A is preferred.
If any calculation were needed after the if and before the return, you would need Statement A in any ways, so isn't it more consistent?

I'm totally over trying to get code into super compact pieces after seeing a 140 line program shoved into a one liner in a coding competition :D Took me 140 hours to figure out what it does!


At the beginning of my career I used to use the if-else syntax. Now I see just if syntax more readable


I'd definitely go for early returns.
less indentation, the logical steps are easier to follow, less code to read when you navigate through breakpoints while debugging.
also easier to further refactor if the single if statements get too long or complicated -> just move them to another function, which by the way would be unit-testable too.


In favor of not having a if/else block if I can avoid it.

return typeof val === 'string' && 'A' ||
     val === null || val === undefined && 'B' || val;

or to be a little more descriptive

const isString = typeof val === 'string';
const isEmpty = val === null || val === undefined;

return isString && 'A' || isEmpty && 'B' || val;

I do like the if/else case. Where sometimes when you are actually reading the codes it gives a better insight on the app and just like piece of orchestration or a music it makes sense (it rythms). It does sound and it is a good coding practice.


I always try to save as much space as I can, so I guess it's the choice B for me.

spaceSaving ? if : if/else;

Statement B in general, because of indentation and context, even though you need to be careful about conditional cases. It's generally easier to follow through. IT REQUIRES MUCH LESS COGNITIVE LOAD because you don't need to think about all the cases that might have happened before or might happen afterwards if the specific condition is true or false. It's mostly used when you want to quickly check for a very bad usage of a function. Parameters that might break your logic. In that case you'd have 1-2-3 if clauses that check for bad params and immediately return/throw error. Alternative to that is to let the bad param checking leak to ALL of you NESTED conditional cases and make your code very hard to read. In that case you need to check for valid params inside of nested code and it's quite possible that similar code will occur a couple of times in the same function, which is crazy.
If you at any point end up thinking that it's not enough, that you need to take care of a bunch of complex cases, your function needs to be broken down to a smaller and composable functions that each do 1 thing and then revise all of the surrounding logic.


I see a ton of comments on this thread and i read through about half.
I don't see anyone making a case for method A.

I prefer method A because conditionals rarely do just one thing inside them like these comments would have you think.

//one line here
}else if(anotherthing){
//one line here

If this were always the case, then having just if statements after each other is simple and easy to read and maintain.

More often than not it's "//50 lines here" in between the conditions, and if you're not using squigglies (brackets) then your code quickly becomes unreadable. You won't know what conditional you're inside of even with indentation.

And yea, someone's gonna go "You should never have 50 lines inside a conditional!"
Ok, so you'd have a conditional that calls a method that calls another 5 extracted methods in other files right? because THAT solves the problem, when it really just makes your code more convoluted and harder to follow.

Also, does it really hurt so much to just write "else" in front of an if statement? So you always KNOW that this is A. not the only condition, and B. not the last condition either.

In the long term it's never good to minimize your code like that. You always end up with someone going in to add something to the conditional and because they added a second line it now breaks because of a lack of squigglies. The code executes the second line always because it's not "inside" the if statement.

It's just better practice to always wrap things so they're maintainable in the long term.

My 2 cents.


I vote for a mixed style: return early if there is an obvious default case (a guard) then use an if/else for some set of related cases. My reasoning is below.

I first ran into this waaaay too long ago in a code review with someone who said "a method should have one exit point" whereas i was liking the "exit early" or "guard" approach. I argued "but if you use early returns you don't have the cognitive overhead of needing to reading the whole method". Yet to them "single return" was The One True Way so we agreed to differ. My guideline for what to do when two devs disagree on a purely stylist matter is that the code remains as-is. I actually cannot remember whether it was my code or their code that was under review.

Unfortunately early returns is often a rotten code smell of "couldn't be bothered to refactor to add a new feature". In that anti-pattern you have a God Object / God Function and to add new features you add a fresh block at the top of the enormous "doAnything" method to detect your new scenario, call your new feature logic in another file, then return early. Then "ta da!" you never have to refactor the God code or change its unit tests (which are incomplete) nor manually test anything other than your new feature case. This leads to an immediate Broken Glass model where the next dev copies that approach. Pretty soon you have a thousand line method that keeps on growing with every new feature added. Regrettably large OO code bases that have seen any team turnover tend to default to this sort of thing remarkably fast.

If you tempted to return early in more than a single obvious default case then perhaps you should break up the class or method into different units that can be composed where each unit has an if/else set for some closely related cases. You then end up with smaller functions or classes that handle a tight set of cases. Then you can take a mixed approach. Try to only return early if there is a really common default case. Why? Because during debugging you don't want someone to have to read the whole code if there is a very common case. The more early returns you put in the more the code is asking to be broken up. The more complex the if/else starts the more you should break it up into different units that handle a more narrow set of cases.


I prefer the second approach, but with curly braces.

Generally speaking, I return ASAP like you did to avoid nested code and big if/else statements.


I prefer just if with early returns as it reduces nesting conditions.


If present then Stick to codebase convention
Else prefer readbility of the method



Well which one is more "readable"? 🤔😎


As our phylosophy teacher used to say: we are debating about angels gender... Anyway I think I stick more for the first one. I work in Java and there is a plenty of other situation to use one-liners.


I think the original way is clear and more readable.


I talked about that in one of my articles, using Python instead.

What I found out is that there's not just one good answer for these types of questions.

Feel free to read the comments there to, I found all of them pretty interesting, and they can apply to JavaScript to :)


The second approach is nice if and only if all of your branches result in a return; however, it's not great if you're trying to do something else with the result of evaluating the conditions.


I'd use the second for simple conditions and as 'guards', mentioned below. The more verbose if/else if/else would be used for more verbose conditions.


I'd go w/ B, but I'd break the line. I'm not a fan of single line ifs


don't forget the switch! :) quite often it's a lot cleaner solution than multiple if/else statements


I prefer to use Statement B. Statement A just happens to be concise, and its simplicity will lost only by a slight change.


I'd never code A, always B, no doubt about it. Since the 'return' statement ends execution there and then, IMO the 'else' clauses don't make sense at all.

Easy one I would say.


In Golang if the if statement is returning, the linter will complain about the else statement. In short,

if statement == true {

// This is the else statement

interesting that modern languages are putting in generators and "yield" that have multiple exits that save the stack and then reenter into a new position with the saved stack.


Why is val not already typed? It could be anything?!? I'd rather look into avoiding either of these situations and make sure the type of val is already known.


I find this version even more difficult to read...