Understanding never in TypeScript
Tags: typescript, javascript, webdev, programming
Published: 2021-11-16 12:37:03

---
canonical_url: https://dpnkr.in/blog/understanding-never-in-typescript
description: Understanding 'never' in TypeScript can be quite baffling. If you're like me have had faced similar issue then this blog should be able to explain it with the help of some examples.
---

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 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 end point 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 it's 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 which throws error

## Impossible types

Have you ever seen a variable with the type of `string` & `number` both? Well let's see how TypeScript handles it's 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 which 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 who's 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 error.

![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 which 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 learnt something new, thanks for reading!


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