Start learning free

LESSON 78 OF 348 · CONDITIONAL STATEMENTS

Redundant Else Statement in TypeScript: Early Returns

Lesson Read the full explanation

We will learn a simple trick to improve our code quality: removing redundant else statements.

Video Lesson:

STEP 1 OF 1
    Ctrl + Enter to check

    TYPESCRIPT · CONDITIONAL STATEMENTS

    Redundant Else Statement in TypeScript, explained

    What a redundant else is

    An else block is redundant when the if block before it always ends the function. Here is the method from the exercise:

    class Solution {
        negative(n: number): number {
            if (n < 0) {
                return n;
            } else {
                return -n;
            }
        }
    }
    

    The method returns n when n is negative and -n otherwise. It works. But look at what happens after return n: the method is over. The code after the if block can only run when the condition was false, so wrapping that code in an else says nothing the reader did not already know. It also adds a pair of braces and a level of indentation.

    The fix: remove the else

    Delete the else and keep its contents, unwrapped, after the if block:

    class Solution {
        negative(n: number): number {
            if (n < 0) {
                return n;
            }
            return -n;
        }
    }
    

    The behaviour is identical for every input. The code now reads as a rule followed by the general case: "if n is negative, return it as it is; otherwise return its negative". The line return -n; sits at the same indentation level as the if, which is the main path of the method, instead of being tucked inside a branch.

    Why it is safe: return ends the method

    A return statement stops the method immediately and sends a value to the caller. No statement after it in the method runs for that call. When the if block ends in a return, the lines after the block are reached only by calls where the condition was false. That is exactly what else would have meant.

    The same holds for any statement that leaves the current code path: throw in any function, and break or continue inside a loop. If the if block always ends with one of these, an else after it is redundant.

    When you must keep the else

    The trick depends on the if block always ending the function. If it can finish normally, removing the else changes the program. Compare these two functions:

    function withElse(n: number): void {
        if (n < 0) {
            console.log("negative");
        } else {
            console.log("not negative");
        }
    }
    
    function withoutElse(n: number): void {
        if (n < 0) {
            console.log("negative");
        }
        console.log("not negative");
    }
    
    withElse(-1);
    withoutElse(-1);
    
    negative
    negative
    not negative
    

    The first call prints one line. The second call prints two, because the first block does not return, so execution falls through to the line after it. Before you delete an else, check that every way through the if block ends with return or throw.

    Guard clauses

    The same idea scales to functions with several special cases. Each case returns early, and the last line handles what is left:

    function describe(n: number): string {
        if (n < 0) {
            return "negative";
        }
        if (n === 0) {
            return "zero";
        }
        return "positive";
    }
    
    console.log(describe(-5), describe(0), describe(8));
    
    negative zero positive
    

    The alternative, a chain of else if and else blocks, works too, but every extra case adds a level of nesting. With early returns, the code stays flat, and each check is easy to read on its own. Checks at the top of a function that return early are called guard clauses.

    The exercise

    The lesson gives you the method above, with its else, and asks you to remove the redundant part without changing what the method returns. The change is small:

    1. Confirm that the if block ends with return n;, so the function ends there.
    2. Delete else { and its closing brace.
    3. Keep return -n; after the if block's closing brace.
    4. Re-indent that line to the level of the if.

    The braces matter: the if keeps its own closing }, and only the one that closed the else goes away.

    Be careful not to delete the final return -n; along with the else. The compiler does not stop you in these lessons, and positive inputs would then fall off the end of the method and give back undefined.

    Key takeaways

    • An else after an if block that always returns adds nothing.
    • Removing it keeps the behaviour and reduces nesting.
    • Only do it when the if block always ends with return or throw, or with break or continue inside a loop. Otherwise the code after the block runs in both cases.
    • Several early returns in a row, called guard clauses, keep the main logic at the top level of the function.
    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free