Stop using the type “any” in Typescript. Use “unknown” instead.

You’ll be a better TypeScript developer for it.

Yoseph
3 min readFeb 9, 2022

We’ve all thrown "any” over a TypeScript error before.

You’re working on a piece of code, hacking away on the next great electron app, and you quickly want to add a function to handle user input. So you define your variables as the any type and bang the whole thing out. As a JavaScript developer who apparently dabbles in type safety though, you can and should do better.

Use “unknown” instead.

When it comes to best practices, use unknown whenever you are unsure about a type. unknown provides an elastic type safety that allows for type narrowing at a later point in the code execution. This enforces type safety while still allowing code to handle a loose sieve of inputs.

“any” turns off TypeScript.

The alternative, any is essentially telling TypeScript, “hello you useful but also incredibly annoying transpiler, please don’t do the one thing you’re excellent at: provide type safety.” And why put yourself through the pain of tooling your project for TypeScript only to just turn TypeScript off?

Consider the following example.

let x: any = 'one';
x = x ^ 2;
console.log(x);
// output: NaN

By setting the value of x to any the value can be manipulated by a math operator, leading to an undefined output. Instead of working with a number now, we’re dealing with a NaN value. It’s because we’ve told TypeScript “don’t worry about it. Go away!”

While any disables TypeScript, unknown is saying to TypeScript, “I’ll get to that later.” Maybe you literally do not know what is being passed in to your program. You can figure out the definite type later. How? Let me introduce to you another concept: Type Narrowing.

What is Type Narrowing?

Type Narrowing is when a variable is narrowed in scope from a less precise to more precise type. There are many ways to type narrow in TypeScript, including:

  • instanceof type guard
  • conditional value check
  • typeof type guard
  • in type guard
  • type guard function with a type predicate

Here’s a trivial example of using unknown with type narrowing in modern Typescript:


const x: unknown = 1;
if (typeof x === "number") {
x = x ^ 2;
} else {
throw new Error('Expected x as \'number\'.')
}
console.log(x);

Here, Type Narrowing is used to ensure that only values of type number are squared. We’ve added a special form of code called a type guard to narrow to a type we desire.

“So why have the any type in TypeScript anyway?”, you might be asking.

Well unknown was only introduced in Typescript 3.0, so the flexible type protection it does provide came far after the any type. But I also don’t think the any type was a mistake. JavaScript is fast and loose for a reason. And sometimes you don’t want the rigidity of types to get in the way of your development. Optionally ‘disabling’ TypeScript to just create functionality is a necessary loophole for productive TypeScript development. So my best guess is like most quirks of JavaScript, it’s just because it was made by people for the world, and people are complicated, and so is the world, so JavaScript never had a chance to be anything but complicated.

You can learn more about Type Narrowing here: 6 ways to narrow types in TypeScript | Building SPAs (carlrippon.com)

You can learn more about ‘type narrowing’ and ‘type guards’ here: TypeScript: Documentation — Narrowing (typescriptlang.org)

You can learn more about ‘unknown’ here: TypeScript: Documentation — More on Functions (typescriptlang.org)

You can learn more about the ‘typeof’ operator here: TypeScript: Documentation — Typeof Type Operator (typescriptlang.org)

--

--

Yoseph

Software Engineer passionate about the future of cities. Currently building libraries for Azure IoT.