Post cover

unknown vs any in TypeScript

Updated January 6, 2023

A variable of type any can be assigned with anything:


let myVar: any = 0;
myVar = '1';
myVar = false;

Many TypeScript guides discourage the use of any because using it throws away the type restrictions — the first reason why you use TypeScript!

TypeScript (version 3.0 and above) also provides a special type unknown that is similar to any. You can assign any value to an unknown type variable as well:


let myVar: unknown = 0;
myVar = '1';
myVar = false;

Now... the big question is: what is the difference between using any and unknown?

Let's find out in this post.

1. unknown vs any

To better understand the difference between unknown and any, let's start with writing a function that wants to invoke its only argument.

Let's make the only parameter of invokeAnything() as any type:


function invokeAnything(callback: any) {
callback();
}
invokeAnything(1);

Because callback param is of any type, the statement callback() won't trigger type errors. You can do anything with a variable of type any.

But running the script throws a runtime error: TypeError: callback is not a function. 1 is a number and cannot be invoked as a function — and TypeScript hasn't protected you from this error!

How to allow invokeAnything() function to accept any kind of argument, but force a type check on that argument, for example, if invoking it as a function?

Welcome unknown!

An unknown type variable, same as any, accepts any value. But when trying to use the unknown variable, TypeScript enforces a type check. Exactly what you need!

Let's change the type of callback param from any to unknown, and see what happens:


function invokeAnything(callback: unknown) {
callback(); // Type error: 'callback' is of type 'unknown'
}
invokeAnything(1);

Because the callback argument is of type unknown, the statement callback() has a type error Object is of type 'unknown'. Now, contrary to any, TypeScript protects you from invoking something that might not be a function!

You need to perform type checking before using a variable of type unknown. In the example, you would simply need to check if callback is a function type:


function invokeAnything(callback: unknown) {
if (typeof callback === 'function') {
callback();
}
}
invokeAnything(1);

Having added typeof callback === 'function' check, you can safely invoke callback() because unknown has narrowed to Function type. No type errors and no runtime errors! Great!

2. The mental model of unknown vs any

To be honest, I had difficulties understanding unknown when I had been learning it. How does it differ from any, since both types accept any value?

Here's the rule that had helped me understand the difference:

  • You can assign anything to unknown type but you have to do a type check or type assertion to operate on unknown
  • You can assign anything to any type and you can perform any operation on any

The example above has demonstrated exactly the similarity and difference between unknown and any.

The case of unknown:


function invokeAnything(callback: unknown) {
if (typeof callback === 'function') {
callback();
}
}
invokeAnything(1);

The type check here is typeof callback === 'function' — checking whether the callback is a function. The type of callback narrows to function type.

The case of any:


function invokeAnything(callback: any) {
callback();
}
invokeAnything(1);

callback being any, TypeScript doesn't enforce any type checking for the statement callback().

3. Conclusion

unknown and any are 2 special types that can hold any value.

unknown is recommended over any because it provides safer typing — you have to use type assertion or narrow to a specific type if you want to perform operations on unknown.

Challenge: can you write a utility type IsUnknown<T> which evaluates to true if T is unknown and false otherwise?

Like the post? Please share!

Dmitri Pavlutin

About Dmitri Pavlutin

Software developer and sometimes writer. My daily routine consists of (but not limited to) drinking coffee, coding, writing, overcoming boredom 😉. Living in the sunny Barcelona. 🇪🇸