Close

TypeScript - Using never Type

[Updated: Oct 28, 2018, Created: Oct 28, 2018]

The type never is used where the code which uses it should never be reachable. Even compile time checker can recognize such unreachable cases.

Examples

function loopForever(): never {
    while (true) {
    }
}

Above code compiles without any error even though we are actually not returning anything from the function. TypeScript compiler can see that this method will never return because of the infinite while loop.

See another example:

function terminateWithError($msg): never {
    throw new Error($msg);
}

Here also compile time checker can recognize that 'terminateWithError' function will never return because of the exception thrown.

Difference between void and never

The function which returns void does not terminate execution i.e. it returns without any value and execution goes on. But function with 'never' return types never returns i.e. execution terminates or function caught in a scenario like an infinite loop. Generally, the type 'never' is meant to find the bugs during compile time, and it should be used at what the developer expects a logically unreachable place.

Exhaustiveness checking

The type 'never' can be very useful to check exhaustiveness of all possible type guards.

Example:

function checkExhaustiveness(x: never): never {
    throw new Error("exhaustive check fails for: " + x);
}

function showTruFalse(x: string | boolean): void {
    if (typeof x === "string") {
        console.log("string: " + x);
    } else if (typeof x === "boolean") {
        console.log("boolean: " + x);
    }
    else {
        checkExhaustiveness(x);
    }
}

showTruFalse(true);
showTruFalse("false");

Output

boolean: true
string: false

During compile time, TypeScript can see that all possible type guards are used and that else block which assigns x to never type will never be executed during runtime, so the compiler deduces that x's type at that point is 'never' because this code is unreachable.

Now let's miss one type guard:

function checkExhaustiveness(x: never): never {
    throw new Error("exhaustive check fails for: " + x);
}

function showTruFalse(x: string | boolean): void {
    if (typeof x === "string") {
        console.log("string: " + x);
    }
    else {
        checkExhaustiveness(x);
    }
}

showTruFalse(true);
showTruFalse("false");

Output

type-never-exhaustive-check2.ts(10,29): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'never'.

This time there's a compile time error. The error is : Argument of type 'boolean' is not assignable to parameter of type 'never'.
The compiler is smart enough to see that boolean is not used in any if/else blocks, so it gives compile time error in the else block on assignment of x to never type. The value of x at that point would be of boolean type during runtime.

We could have just assigned 'x' to the type 'never' instead of calling another function to achieve the same result:

function showTruFalse(x: string | boolean): void {
    if (typeof x === "string") {
        console.log("string: " + x);
    }
    else {
        let temp: never = x;
    }
}

showTruFalse(true);
showTruFalse("false");

Output

type-never-exhaustive-check3.ts(6,13): error TS2322: Type 'boolean' is not assignable to type 'never'.

Example Project

Dependencies and Technologies Used:

  • TypeScript 3.1.3
Using TypeScript 'never' type Select All Download
  • typescript-never-type
    • type-never-exhaustive-check.ts

    See Also