As developers, it seems like we're in a land of plenty when it comes to code quality tools. There are many options, some more controversial than others. One such option is ESLint in Javascript with the consistent-return rule.

When you enable the consistent-return rule in ESLint the tool will automatically check that all code paths in a function either explicitly return a value or don't return a value. In functions that branch one might forget to return a value in one of the branches, and the consistent-return rule will warn you when that happens.

This rule can be controversial though because it disallows using return statements as control flow. I think this is the biggest benefit of the consistent-return rule, but others on my team think this is a large drawback. Consider the following code to charge an order:

class Order {  
  charge() {
    // if there are no items, then there's nothing to charge
    if (this.items.length === 0) { return; }

    // charge order
    const chargeToken = magicChargeHelper(this);

    return chargeToken;

The above code attempts to charge an order. If there aren't any items in the order it returns early, skipping the code that actually charges the order. This code may seem fine, but the consistent-return rule will raise an error because we aren't returning a value from the conditional branch. We are using inconsistent return semantics. To remove the flag, simply return a value from that branch. Any value will do, even null or undefined. This restores consistent return semantics; we're consistently using return to pass values rather than sometimes as control flow and sometimes to pass values.

While this follows the letter of the rule, it does not satisfy its spirit. When this rule flags your code, it's really telling you that you might not have considered every edge case in your code. In the above example, we should consider how orders can ever have no items in them. There might be a data corruption issue that is hiding somewhere that we need to address. This might be a bug fix that doesn't address the root cause. I would only fall back to this kind of conditional guard if I'd exhausted all other options. Even so there are drawbacks. Using conditionals as control flow makes the control flow difficult to comprehend. Additionally, we now need to make sure the caller of the function handles the case where the return value is not present.

I think that the consistent-return rule for ESLint provides consistent returns on all of my Javascript projects. It forces me to consider all possible edge cases. This helps to cut down on potential sources of bugs and leads to a more consistent and comprehensible design. Reducing the chance for bugs or misunderstandings in your code is worth the small cost.