# Understanding never in TypeScript

I never really understood `never` in my life because to understand `never` you have to use the word never again and again.

So understanding `never` can be quite baffling. If you're like me and ever had faced a similar issue then this blog should be able to explain it with the help of some examples.

Before taking you through the examples this is how TypeScript explains characteristics of `never` in their [release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#the-never-type).


- `never` is a subtype of and assignable to every type.
- No type is a subtype of or assignable to `never` (except `never` itself).
- In a function expression or arrow function with no return type annotation, if the function has no `return` statements, or only `return` statements with expressions of type `never`, and if the endpoint of the function is not reachable (as determined by control flow analysis), the inferred return type for the function is `never`.
- In a function with an explicit `never` return type annotation, all `return` statements (if any) must have expressions of type `never` and the end point of the function must not be reachable.


Let me break it down for you.

## Basics

Let's start with a simple example

```ts
const logName = (s: string) => {
  console.log(`Your name: ${s}`);
};
const returnName = (s: string): string => {
  return `Your name: ${s}`;
};
```

Now if you look at the type declaration of these functions it's easy to understand `logName` returns `void` and `returnName` returns `string` type.

```ts
declare const logName: (s: string) => void;
declare const returnName: (s: string) => string;
```

Now if we log the `logName` function we get `undefined`.

This happens because a function that doesn't explicitly return a value, implicitly returns the value undefined in JavaScript.

```ts
const logName = (s: string) => {
  console.log(`Your name: ${s}`);
};
console.log(logName('Deepankar'));
// Your name: Deepankar
// undefined
```

I added this example to explain that even if `void` seems to not return any value but still returns `undefined` this is inferred as `void` in TypeScript.

## Functions that never return

So what does happen if a function literally doesn't return anything? Well let's look at some examples.

```ts
const runInfinitely = () => {
  while (true) {
    console.log('Running');
  }
};

const throwError = () => {
  throw new Error('Bruh');
};
```

Now looking at its type declarations

```ts
declare const runInfinitely: () => never;
declare const throwError: () => never;
```

Awesome so we finally see the `never` type now let's understand why

`runInfinitely()` runs in an infinite loop and never breaks/returns anything and `throwError()` runs and throws an exception which stops the program to run and never returns.

From these examples, we can conclude that Typescript infers the return type as `never` if a function expression

- never breaks/returns anything
- has a throw statement that throws an error

## Impossible types

Have you ever seen a variable with the type of `string` & `number` both? Well, let's see how TypeScript handles its type.

```ts
const impossibleType = string & number;
```

![impossible type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5ou287wt31xlysxvmk1.png)

Now if we hover over the variable in vscode we should be able to see that `impossibleType` has `never` type.

Hence TypeScript will use a `never` type to represent a type that is impossible to exist.

## Exhaustive Checks

From the [TypeScript handbook](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#exhaustiveness-checking)

When narrowing, you can reduce the options of a union to a point where you have removed all possibilities and have nothing left. In those cases, TypeScript will use a `never` type to represent a state which shouldn’t exist.

The `never` type is assignable to every type; however, no type is assignable to never (except never itself). This means you can use narrowing and rely on never turning up to do exhaustive checking in a switch statement.

To understand this take the following example

```ts
const notPartOfLife = (n: never) => {};

type Life = 'Eat' | 'Sleep' | 'Code';

const liveLife = (life: Life) => {
  switch (life) {
    case 'Eat':
      return 'Eating';
    case 'Sleep':
      return 'Eating';
    case 'Code':
      return 'Coding';
    default:
      return notPartOfLife(life);
  }
};
```

Here `liveLife` is a function that has a switch case whose default case would never run because it exhausts all the cases of `Life` type.

TypeScript is intelligent enough to infer the type as `never` if the conditional block is impossible to happen and that's why `life` is inferred as `never`.

![Typescript being intelligent](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si8bmy6gpkqzubksypt8.png)

Now let's add another value to the `Life` type

```ts
const notPartOfLife = (n: never) => {};

type Life = 'Eat' | 'Sleep' | 'Code' | 'Play';

const liveLife = (life: Life) => {
  switch (life) {
    case 'Eat':
      return 'Eating';
    case 'Sleep':
      return 'Eating';
    case 'Code':
      return 'Coding';
    default:
      return notPartOfLife(life);
  }
};
```

Upon doing this we should be able to see this beautiful Typescript error. But don't worry it's helping us out here. Typescript was able to infer that type of `life` would be `Play` which is a string but `notPartOfLife` function needs a param of type `never`.This mismatch of types causes TypeScript to throw errors.

![Mismatch in types](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/updvij1jkqdvnhzaihvb.png)

Fixing this is easy we will just add the case for `Playing`.

```ts
const notPartOfLife = (n: never) => {};

type Life = 'Eat' | 'Sleep' | 'Code' | 'Play';

const liveLife = (life: Life) => {
  switch (life) {
    case 'Eat':
      return 'Eating';
    case 'Sleep':
      return 'Eating';
    case 'Code':
      return 'Coding';
    case 'Play':
      return 'Playing';
    default:
      return notPartOfLife(life);
  }
};
```

And now the error is gone!

## Recap

- TypeScript will use a `never` type to represent a type that is impossible to exist.
- The `never` type is assignable to every type; however, no type is assignable to never (except never itself).
- TypeScript will infer `never` as return type if the function never returns / throws error.

Hope you’ve learned something new, thanks for reading!


> **A quick favor:** was anything I wrote incorrectly or misspelled, or do you still have questions? Feel free to message me on [twitter](https://twitter.com/DeepankarBhade).

