Use of never keyword in typescript

Typescript

Typescript Problem Overview


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.

Typescript Solutions


Solution 1 - Typescript

  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"
}

3. 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

Solution 2 - Typescript

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) {
    }
}

Solution 3 - Typescript

> 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
    }
}

Solution 4 - Typescript

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); }

Solution 5 - Typescript

One example is if you throw an error. E.g.

function throwError () {
  throw new Error('whoops');
}

You can find some more info here: https://basarat.gitbooks.io/typescript/content/docs/types/never.html

Solution 6 - Typescript

never is the type with 0 values.

Just as boolean is either true and false, which means there are and only are 2 ways to construct a value of type boolean, in TypeScript there are exactly 0 ways to construct a value of type never.

But you may ask, "how is never any useful then?"

In TypeScript, values are produced by expressions. Expressions have types too, which are the same as the type of the values they evaluate to. parseInt("123") is type number while [1, 2, 3] is type number[]. But not all expressions can be evaluated to values. Consider:

function f() {
  return f()
}

An expression f() will get you nowhere. f() returns f() which returns f() and on and on and this recursion continues until maximal recursion limit is reached and the program crashes.

So f() does not evaluate to any value anyway. But this expression still needs to have a type; which?

The answer is that any type would do. It won't give us a chance to use its return value after all (because it does not have one; also because it will run indefinitely) so we can write

function f(): number {
  return f()
}

so that f() is type number; or even write

function f<T>(): T {
  return f()
}

But usually, we write never:

function f(): never {
  return f()
}

So never plays a new role here; it is a type that does not have values, so it marks that the expression is special, that it will cause the program to do something other than produce a value, such as keep running indefinitely.

More often, you will see never with code that is sure to throw an error, or cause the program to terminate:

function throwSomeError(): never {
  throw new Error()
}

function bye(): never {
  process.exit(0)
}

These functions won't return any value either, so we could have chosen any type for their "return type" that actually, does not exist, but we usually use never to signify that these functions are very special ones.

Solution 7 - Typescript

If write a custom param decorator in nest js:

export const CurrentUser = createParamDecorator(
  (data: never, context: ExecutionContext) => {
    //   what ever we provide arg to the CurrentUser('arg') will be shown as `data`. this decorator does not need any arg
    // never meaans this argument will never be used
    return 'I return the user';
  },
);

this is how I use it inside controller:

 @Get('/me')
   me(@CurrentUser() user: string) {
      return user;
   }

If I pass an argument to CurrentUser() when I used it, that will be shown as 'data' inside the CurrentUser. Since I do not need to pass any arg, I used "never" as "data"s type above.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNeoAshView Question on Stackoverflow
Solution 1 - TypescriptKrzysztof GrzybekView Answer on Stackoverflow
Solution 2 - TypescriptMark EdingtonView Answer on Stackoverflow
Solution 3 - TypescriptWillem van der VeenView Answer on Stackoverflow
Solution 4 - TypescriptApurva PathakView Answer on Stackoverflow
Solution 5 - TypescriptSebastian SebaldView Answer on Stackoverflow
Solution 6 - TypescriptdaylilyView Answer on Stackoverflow
Solution 7 - TypescriptYilmazView Answer on Stackoverflow