In TypeScript, there’re 2 data types that can hold anything.
They’re the any
and unknown
types.
Since they have different names, they’re different.
In this article, we’ll look at the difference between them and what can we do with them.
The any Type
The any
type variable lets us assign anything to it.
If it’s used as a parameter, then we can pass in anything.
For example, we can write:
function func(value: any) {
const foo = 5 * value;
const bar = value[1];
}
The TypeScript compiler doesn’t restrict what we can do with a variable or parameter that has an any
type.
If we have a variable, we can assign anything to it.
For instance, we can write:
let bar: any;
bar = null;
bar = true;
bar = {};
We can assign anything to a variable with the any
type.
Also, we can assign an any
variable to variables, with any type:
function func(baz: any) {
const a: null = baz;
const b: boolean = baz;
const c: object = baz;
}
A real example would be JSON.parse
. Its signature in TypeScript’s type definition is:
JSON.parse(text: string): any;
The unknown
type doesn’t exist yet in TypeScript with it’s added to the type definition, so the any
type is used as the return type.
The unknown
type is a better alternative to any
for typing things that don’t have a known structure.
The unknown Type
The unknown
type is a safer version of any
.
This is because any
lets us do anything, but unknown
has more restrictions.
Before we can do anything with a value with an unknown
type, we’ve to make the type known first by using type assertions, equality, type guards, or assertion functions.
To add type assertions, we can use the as
keyword.
For example, we can write:
function func(value: unknown) {
return (value as number).toFixed(2);
}
Since we casted the value
parameter to a number with as
, we can call the toFixed
method with it to round the number.
The TypeScript compiler can also determine the data type with equality comparison.
For example, we can write:
function func(value: unknown) {
if (value === 123)
const rounded = value.toFixed(2);
}
}
We check if value
is 123.
This way, if it is, then the TypeScript compiler knows it’s a number.
So we can call toFixed
on it.
We can do the same with type guards.
To use them, we use the typeof
operator to check the type.
So we can write:
function func(value: unknown) {
if (typeof value === 'number')
const rounded = value.toFixed(2);
}
}
and the compiler will also know that value
is a number.
We can also use assertion functions to do the same thing.
For example, we can write:
function func(value: unknown) {
assertNum(value);
const rounded = value.toFixed(2);
}
function assertNum(arg: unknown): asserts arg is number {
if (typeof arg !== 'number') {
throw new TypeError('not a number');
}
}
We create a assertNum
function to check if arg
is a number.
If it’s not, then an exception is thrown.
We then call it in our func
function before doing any operation.
This way, the compiler also knows value
is a number.
Conclusion
The any
type is too flexible for most cases.
unknown
type lets us store anything, but we’ve to determine the type of it before doing anything.