TypeScript - Any Vs Unknown

Introduction

TypeScript provides static type safety which helps us from type-related bugs at run time. That's is why we are using TypeScript in our projects. But sometimes we are using type "any" which is against using the TypeScript (type restrictions). Why against? Then what should we do? In this article, we are going to see about any vs unknown type in TypeScript.

Any

  • If the type of the variable is "any" then we can assign any type of value (string, number, boolean, etc) to the variable. 
  • It is similar to assigning the variable in JavaScript.

Example

let anyVariable: any = 0;
anyVariable = 'Test';
anyVariable = false;
  • Actually, it is not good practice to use "any" type, because using "any" throws away the type restrictions. The first reason we are using TypeScript is type safety. But the type "any" has thrown away this restriction.
  • Using "any" will lead to a run time error. 

In this below example, there is no run time error.

function invokeCallback(callbackFn: any) {
    callbackFn();
}
function callbackFunction() {
    // logic
}
invokeCallback(callbackFunction);

Let consider the below example,

function invokeCallback(callbackFn: any) {
  callbackFn();
}
invokeCallback(1);  // throws "TypeError: callbackFn is not a function"

In the above example, "callbackFn" parameter is any type, so it accepts "1", but the statement callbackFn() throws "TypeError: callbackFn is not a function" run time error. Because "1" is a number, not function.

Unknown

  • The unknown type comes into the picture to resolve the above run time error.
  • The "unknown" type introduced in TypeScript 3.0 is also considered a top type. 
  • It is similar to any, which means it accepts all types of values (string, number, boolean, etc.). But the difference is, if you are using an "unknown" type then, TypeScript is enforce the type check before using the variable. 

Let’s change the type of callbackFn param from any to unknown.

function invokeCallback(callbackFn: unknown) {
  callbackFn();
}

invokeCallback(1);

In this above example, the TypeScript throws "Object is of type 'unknown'." error in the callbackFn() statement. Because the callbackFn argument is of type unknown. Now, TypeScript protects from invoking something that might not be a function.

To resolve the above error, we need to do type checking of the variable before going to use it. So, just check if callbackFn is a function type or not.

function invokeCallback(callbackFn: unknown) {
  if (typeof callbackFn === 'function') {
    callbackFn();
  }
}

invokeCallback(1);

Now you can safely invoke callbackFn() with just adding the type check typeof callbackFn === 'function'. No run time type errors!

More info about "unknown" type

We can assign a variable of the unknown type only to any, and the unknown type.

Example

let unknownVar: unknown = 'Hello'!;
let anyVar: any = unknownVar;
let unknownVar1: unknown = unknownVar;

If wants to perform some operations(particular type-related operation) on the unknown type then, we first need to narrow it to the required type (type conversion).

Example

const strVariable: unknown = "This is Test Value";
(strVariable as string).toLowerCase();

A more type-safe way of narrowing down the unknown type is to use a control-flow narrowing.

Example

const strVariable: unknown = "This is Test Value";
if (strVariable && typeof strVariable === 'string'){
    strVariable.toLowerCase();
}

Summary

  • You can assign any values to unknown type variables, but you cannot use them before doing a type check or type assertion.
  • You can assign any values to any type of variable and you can use it without type check. 
  • The unknown is a more recommended type than any because it provides type-safe.
Any means "I don't care"    Unknown means "I don't know"

I hope you have liked it and know about type any and unknown in TypeScript.