Use of never keyword in typescript

TS documentation says:

the never type represents the type of values that never occur. Variables also acquire the type never when narrowed by any type guards that can never be true.

I didn't understand its usage, can anybody give me an answer with some examples.


  1. "the never type represents the type of values that never occur."

It might be return type of function that never returns:

const reportError = function () {
    throw Error('my error');
}

const loop = function () {
    while(true) {}
}

Here, both reportError and loop type is () => never.

  1. "Variables also acquire the type never when narrowed by any type guards that can never be true"

With operators like typeof, instanceof or in we can narrow variable type. We may narrow down the type the way, that we are sure that this variable in some places never occurs.

function format(value: string | number) {
    if (typeof value === 'string') {
        return value.trim();
    } else {
        return value.toFixed(2); // we're sure it's number
    }

    // not a string or number
    // "value" can't occur here, so it's type "never"
}
  1. Common use case

Except better type safety (as in cases described above), never type has another use case - conditional types. With never type we can exclude some undesired types:

type NonNullable<T> = T extends null | undefined ? never : T;

type A = NonNullable<boolean>;            // boolean
type B = NonNullable<number | null>;      // number

There are multiple examples in the Typescript documentation for never:

// Function returning never must have unreachable end point
function error(message: string): never {
    throw new Error(message);
}

// Inferred return type is never
function fail() {
    return error("Something failed");
}

// Function returning never must have unreachable end point
function infiniteLoop(): never {
    while (true) {
    }
}

the never type represents the type of values that never occur:

The Typescript compiler assigns types to all your variables/properties. These types can be either the typescript defined types like number and string, or user defined types made with the interface and type keyword.

It is useful to think of these types as sets. In other words a type itself is a collection of possible things which your variables/properties can be at that time. For example:

// the variable five can be one thing which is a number
const foo = 5; // type = number; 

// bar can be two things
type twoPrimitives = string | number;
let bar: twoPrimitives = 4; 
  • We see foo has a set size of 1 >> {number}
  • We see bar has a set size of 2 >> {number, string}

Now with our set definition in mind we can define the never type easy:

the never type represents the empty type set >> {}. i.e. a set with 0 items in it.

For example:

// Normally a function which do not have a return value returns undefined implicitly
// However this function throws before ever reaching the end. 
// Therefore the return type will be never
function foo() :never {
   throw new Error("Error");
}

// thisMakesNoSense will be type never, a value can never be number and string at the same time
type thisMakesNoSense = number & string; 

Variables also acquire the type never when narrowed by any type guards that can never be true.

TS can check narrow types if they are explicitly checked in if statements. This is called type guards. In other words a type guard is some expression that performs a runtime check that guarantees the type in a certain scope. For example:

// The compiler actually screens these if statements and can infer that in the third
// else statement there are no more types left for value to take on and thus the type 
// become never. Another way to think about this is that in the first if statement the
// set of possible types shrinks from string | number to number only.
// Then in the seconds if statement it shrinks from number to never
function typeGuards(
    value: string | number
) {
    if (typeof value === "string") {
        value; // Type string
    } else if (typeof value === "number") {
        value; // Type number
    } else {
        value; // Type never
    }
}

Links that I studied from : https://www.typescriptlang.org/docs/handbook/basic-types.html https://basarat.gitbooks.io/typescript/docs/types/never.html https://egghead.io/lessons/typescript-use-the-never-type-to-avoid-code-with-dead-ends-using-typescript https://blog.mariusschulz.com/2016/11/18/typescript-2-0-the-never-type

Can be summarized as the never type is used for cases like :

  1. A function never returns (e.g. if the function body has while(true){})

    //Type () => never
    
    const sing = function() {
    while (true) {
        console.log("Never gonna give you up");
        console.log("Never gonna let you down");
        console.log("Never gonna run around and desert you");
        console.log("Never gonna make you cry");
        console.log("Never gonna say goodbye");
        console.log("Never gonna tell a lie and hurt you");
    }
    };
    
  2. A function always throws (e.g. in function foo(){throw new Error('Not Implemented')} the return type of foo is never)

    // Type (message: string) => never
    const failwith = (message: string) => {
        throw new Error(message);
    };
    

Use case: Exhaustive Checks

function foo(x: string | number): boolean {
  if (typeof x === "string") {
    return true;
  } else if (typeof x === "number") {
    return false;
  }

  // Without a never type we would error :
  // - Not all code paths return a value (strict null checks)
  // - Or Unreachable code detected
  // But because TypeScript understands that `fail` function returns `never`
  // It can allow you to call it as you might be using it for runtime safety / exhaustive checks.
  return fail("Unexhaustive!");
}

function fail(message: string): never { throw new Error(message); }