Secrets of ‘unknown’ Types in TypeScript
Why ‘unknown’ Is preferred over ‘any’ in TypeScript?
This post will introduce the unknown
type in TypeScript, which was introduced in TypeScript 3.0 and is the type-safe counterpart of any
.
Why do I say this? Next, I will show the characteristics of unknown
type and its advantages compared with any
, let's get started!
Assignability
All types are assignable to unknown
, but in turn, unknown
can only be assigned to itself and any
.
Intersection Types
In intersection types, all types will absorb unknown
.
This is not difficult to understand, because the intersection type represents the intersection of the two, and we already know in the previous section that all types are assignable to unknown
, so any intersection with unknown
will be itself.
Union Types
In union types, unknown
absorbs all types except any
.
The union type represents the combination of the two. If the two can be combined, then the one with the more relaxed range will be returned, so it is unknown
except for any
.
Keyword `keyof`
keyof unknown
returns the type never
, representing the type of the value that will never occur. Whereas keyof any
returns the type of any value that can be used as an object index. Why do you say that?
This is because there is a keyofStringsOnly in the TypeScript compilation options, the default is false, then keyof any
will return string | number | symbol
type, When true, keyof any
will return type string
.
It’s worth noting that the built-in advanced type Record
in TypeScript uses this to qualify types that can be used as object indexes. Its source code is as follows:
type Record<K extends keyof any, T> = {
[P in K]: T;
};
For more information on built-in utility types in TypeScript, please check out my previous article:
For the secrets of never
types in TypeScript, check out my other article:
Initialized
unknown
variables declared without const
are always considered initialized.
Restrictions before narrowing types
Except for the equality operators, you cannot use any other operators, such as +-*/
, property access, function calls, etc., without narrowing the type of unknown
.
Narrow type
From the previous section, we know that if we want to manipulate the value of the unknown
type, we must first narrow the type, so that the TypeScript compiler knows what we are doing, and your code is guaranteed to be safe.
Narrowing types can use typeof
, instanceof
, user-defined type predicates, type assertions, etc.
Note that TypeScript doesn’t help us perform any checks when using type assertions, which means you have to know what you’re doing and make sure you’re doing what you want.
Conclusion
The any
type causes the TypeScript compiler to skip type checking for this variable, which can be understood as an escape hatch into the TypeScript type system, but in most cases, it's too lenient. On the other hand, values of type unknown
must be narrowed down to a specific type before most operations are performed, which often means safer and more robust.
Thanks for reading. I hope this was helpful. If you are interested, check out my other Medium articles.