The TypeScript documentation says that
The
never
type is a subtype of, and assignable to, every type
but doesn\'t m
The type that TypeScript calls never
is what's known in type theory as a bottom type, sometimes referred to with the symbol "⊥". The idea is that it is the (unique) type for which there are no values of that type. You should never
find yourself holding a value of that type because it has no values. If you think of types as sets of possible values, then it is the empty set (symbol "∅").
This probably all makes sense to you.
TypeScript also has the notion of subtyping. Just like sets, types can overlap by containing some of the same values. If every value of type A
is also a value of type B
, then A
is a subtype of B
. You can also say that A
extends B
, or symbolically, A <: B
. In TypeScript, {a: string}
is a subtype of object
, because every value of type {a: string}
(for example, the value {a: "hello"}
) is also a value of type object
.
TypeScript's assignability rules are basically related to substitutability. If a variable is of type B
, and A <: B
, then you can assign a value of type A
to that variable, because every value of type A
is also a value of type B
. You can't necessarily do the reverse, assigning a value of type B
to a variable of type A
. Unless B <: A
, there are some values of type B
which are not values of type A
.
From the types-as-sets-of-values point of view, A <: B
is like saying the set of values of type A
is a subset of the set of values of type B
, (symbols A ⊆ B
).
This probably (I hope) all makes sense to you too.
One more thing we need: the logical principle of explosion. If you start with a statement that is false, then you can prove anything at all from it. So, assuming "the moon is made of cheese" is false, then "If the moon is made of cheese, then today is Wednesday" is true. Also, "if the moon is made of cheese, then today is not Wednesday" is true. There are dire consequences for taking something false to be true: everything explodes.
How type-checking works for assignments?
Take the R-value (right side of assignment). Verify if it can assume a value which the L-value (left side of assignment) can not. If any such value exists, then reject the assignment. Otherwise, it's fine.
Let's see examples:
let x: number;
let y: never;
x = y; // OKAY, can assign any given `never` value to a number
y = x; // Not OKAY, x can be, among other values, 1, which is can not be assigned to never
It looks absurb, as an assignment needs to move some data into the designated storage for a given variable, and no value exists, since it's not a runtime type. In practice though, an assignment from never
to any other type, while valid, won't actually run (except if you trick TypeScript with type assertions).
Does that make sense?
You are not calling the useNever
function. If you try to call it with a parameter it will fail since a value can not be never
. But as always, you can trick the compiler with typeguards e.g. this will work
const test = (val: string | number) => {
if (typeof val === "string") {
} else if (typeof val === "number") {
} else {
useNever(val); // works, since val is not number or string it is implicitly never
}
}