TypeScript odd types: unknown, void, never, any, null and undefined
TypeScript has a very complex and powerful type systems. Yet for some it also constitutes a mystery in its more deep features. Among these, special types can be source of brain freezes for many, so let’s see in detail what they all mean.
The void type represents the absence of any type. It is notably used to describe the return value of functions that do not return anything. No value can be assigned to a variable of type void, except for
undefined. Additionally, if you do not have the
--strictNullChecks option enabled on your TypeScript compiler, you can in principle also assign
null to void variables. However, I highly advised you avoid that and always have
--strictNullChecks enabled, as it enforces a more secure and predictable application behaviour. Besides, it allows you to worry less on whether or not you should check for nullity.
At the opposing end of the spectrum is the any type, which represents literally any type. A variable whose type is
any can be assigned any possible value and it will never produce a compilation error. Similarly, a function that returns
any can return arbitrary objects, atomic values or even nothing, and will still be valid. Additionally, you can always access arbitrary properties and methods from a variable of
any type without the compiler complaining. On the downside, you have no guarantee that the actual value contained there at runtime will abide to your expectations. Working with
The unknown type is similar to
any, in that it also represents a type that is apriori not known. However, it behaves slightly differently than
- any value can be assigned to a variable of type
unknownor returned from a function declared with
- however, while
anycan be assigned without warnings or errors to any other type,
unknowncannot and will cause a compilation error;
- additionally, if you try to access any property or method on a variable of
unknowntype, the compiler will point it out as an error.
unknown is safer to usa than
any, since it restricts all operations you can perform on variables and return values. I also like to think of
unknown as “I don’t care what type it is” and find it especially useful for defining callbacks. Using it for declaring callbacks is one of my favourite usages:
The never type is very interesting. It represents the type of values that can never occur. While in principle it may make little sense, it does have many interesting application:
- functions that always throw an exception implicitly have
neveras their return type;
- functions that trivially cannot terminate also have a
neverreturn type, but of course there is a limit to the compiler’s ability to detect this scenario;
- when a union or more complex type is progressively narrowed down through subsequent type guards and eventually reach a point where all options have been exhausted and there is no other possible type left. The type of the analyzed expression is
neverin this case.
Null and undefined
Null and undefined are singleton types.
null is the type of the singleton value
undefined is type type of single value
undefined. Duh. If you have the
--strictNullChecks compiler option enabled (as you should), they can only be assigned to
any directly. Otherwise, you need to specify that your values may accept either of those special symbols by using a union type.