Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why was the `never` type introduced in TypeScript?

I have now searched the internet for an explanation of WHY the never type was introduced. Both the TypeScript handbook and the TypeScript Deep Dive exaplains what it is and a few other articles. None of them explains, though, WHY you would use the never type and what it solves. Most of the examples show code, where the compiler already infers never, so why do I have to assign the type? What does it solve. Is it “just” to signal the intellisense what I can do afterwards (i.e. Nothing - which might be useful enough). And what do the compiler use the information for? As always, explanations of WHAT and HOW might help people do stuff, but only WHY makes them understand.

like image 285
Morten H Pedersen Avatar asked Mar 11 '18 11:03

Morten H Pedersen


People also ask

Why is type never in TypeScript?

The reason the error "Argument of type is not assignable to parameter of type 'never'" occurs is because when we declare an empty object, TypeScript infers its type to be never[] - an array that will never contain any elements.

How do I avoid never TypeScript?

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?" An expression f() will get you nowhere.

What is an unknown type and when to use it in TypeScript?

In Typescript, any value can be assigned to unknown, but without a type assertion, unknown can't be assigned to anything but itself and any. Similarly, no operations on an unknown are allowed without first asserting or restricting it down to a more precise type.

Does not exist on type never TypeScript?

The error "Property does not exist on type 'never'" occurs when we try to access a property on a value of type never or when TypeScript gets confused when analyzing our code. To solve the error, use square brackets to access the property, e.g. employee['salary'] .


1 Answers

The never type is TypeScript's representation of the bottom type from type theory. So if you are looking for motivation for and uses of never in TypeScript, you might want to look into the bottom type in computer science in general.


The canonical answer to "why was never introduced to TypeScript" is probably best found by analyzing the commentary on the pull request that introduced it and the two issues that it addresses: a request for a bottom type, and request to better handle unreachable function returns.

The main use for developers is to have a type for functions (or sections of functions) that don't return any value at all, not even undefined. Compare these functions:

function u(): undefined {
    return;
}
const uRet = u();
console.log(typeof uRet); // undefined

function v(): void { }
const vRet = v();
console.log(typeof vRet); // undefined

which return undefined values, with these functions:

function throws(): never {
    throw new Error();
}
const tRet = throws();
console.log(typeof tRet); // does not run

function loops(): never {
    while (true) { }
}
const lRet = loops();
console.log(typeof lRet); // does not run

which don't return values at all, due to an exception or an infinite loop. The never type allows both developers and the compiler to reason about sections of code which can never run.


There are other uses for never but I am not going to try to enumerate them, since you already are aware of code examples. It is illuminating to examine the TypeScript standard library to find the places where never shows up.


Finally, when you ask

Most of the examples show code, where the compiler already infers never, so why do I have to assign the type?

note that even in cases where the compiler infers never for you, it is useful for it to exist in the language, in the same way that string is useful even when it is inferred by the compiler. This seems like a different question about when you might want to explicitly annotate types instead of letting the compiler infer them, and vice versa. But this post is already long and this is probably answered elsewhere.

Hope that helps; good luck!


Edit: There are plenty of reasons a programmer would use never, although many programmers might never need to use it. Let me enumerate some reasons I can think of:

  • If you are writing typings for a JavaScript library where a function throws an exception instead of returning, you can't really do that without never.

  • Generic type parameters default to {} when they can't be inferred by the compiler. It sort of "fails open", since {} is compatible with (almost) all values. There are cases when you'd prefer it to "fail closed" and have it be compatible with no values. You can use never as the default parameter.

  • The union of any type T with never is just T, and the intersection of T with never is never. These rules (among others) let a developer build fairly sophisticated type functions that would be harder or impossible without never. For example, here's Diff<T,U>:

    type Diff<T extends string, U extends string> =
      ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
    

    It is a type function which takes a union of string literals T and a union of string literals U, and returns a union of all the values in T which are not present in U.

    You can use it to, among other things, remove a property from a type:

    type Foo = { a: string, b: number, c: boolean };
    type FooWithoutB = Pick<Foo, Diff<keyof Foo, 'b'>>;
    // equivalent to { a: string, c: boolean }
    

It's kind of like the number zero in mathematics. You don't need it; many cultures got along okay without the concept of zero. But it's incredibly useful and allows you to easily express ideas that would otherwise be cumbersome or impossible.

Hopefully that is a little more compelling? Anyway, good luck again.

like image 91
jcalz Avatar answered Sep 20 '22 19:09

jcalz