One of the most common introductory TypeScript interview questions is:

What is the difference between any and unknown in TypeScript? When should you choose one over the other?

Both types are used when we do not know the type of a value ahead of time (for example, when parsing third-party JSON API payloads). However, they interact with the TypeScript compiler in fundamentally different ways.


1. The Core Difference: Type Safety#

The key difference lies in whether the compiler enforces type safety checks:

  • any is unsafe: It effectively disables the type checker. You can access any property, invoke it as a function, or assign it to any type without compile-time errors.
  • unknown is safe: It represents a value that could be anything, but you must perform type narrowing (type checks) or type assertion before you can perform any operations on it.
       any (Opt-out of checking)
       ┌────────────────────────┐
       │ value.foo();           │ ◄── Allowed (Unsafe: may crash at runtime)
       │ value.bar = 10;        │
       └────────────────────────┘

       unknown (Safe container)
       ┌────────────────────────┐
       │ value.foo();           │ ◄── Compile Error (Safe: compiler blocks access)
       │ if (typeof value ===   │
       │    'function') {       │
       │    value();            │ ◄── Allowed after narrowing!
       │ }                      │
       └────────────────────────┘

2. Comparing Behaviors in Code#

A. Operations with any#

TYPESCRIPT
let value: any;

value.trim();       // OK
value();            // OK
value.foo.bar = 10; // OK

At runtime, if value is a number, the first two calls will crash with a TypeError. The compiler will not warn you.

B. Operations with unknown#

TYPESCRIPT
let value: unknown;

value.trim(); // ❌ Compile Error: Object is of type 'unknown'.
value();      // ❌ Compile Error: Object is of type 'unknown'.

To use an unknown value safely, you must narrow its type first.


3. How to Narrow unknown#

There are three common ways to narrow a value of type unknown:

A. Using typeof checks#

TYPESCRIPT
let value: unknown = "hello";

if (typeof value === "string") {
  console.log(value.toUpperCase()); // ✅ Allowed: TypeScript knows value is a string
}

B. Using instanceof checks#

TYPESCRIPT
let value: unknown = new Date();

if (value instanceof Date) {
  console.log(value.getFullYear()); // ✅ Allowed: TypeScript knows value is a Date object
}

C. Using Type Assertion (as)#

If you are certain of the type, you can assert it:

TYPESCRIPT
let value: unknown = getApiData();
const strValue = value as string;
console.log(strValue.trim()); // ✅ Allowed

4. Key Contrast Summary#

Action / Capabilityanyunknown
Can assign any value to it?✅ Yes✅ Yes
Can assign it to another type?✅ Yes (except never)❌ No (only to any or unknown)
Can access arbitrary properties?✅ Yes❌ No
Can invoke as a function?✅ Yes❌ No
Forces type checking?❌ No✅ Yes

Key Takeaways#

  • unknown Type: Use unknown by default when you don't know the incoming type (e.g., fetch request responses, dynamic input fields) to keep the codebase type-safe.
  • any Type: Avoid any unless migrating legacy JavaScript or writing complex generic libraries where type safety is managed via other assertions.
  • Top Type Behavior: Both any and unknown are top types (all values are assignable to them), but unknown cannot be assigned to anything else without narrowing.