TypeScript: any vs. unknown
One of the most common introductory TypeScript interview questions is:
What is the difference between
anyandunknownin 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:
anyis 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.unknownis 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
let value: any;
value.trim(); // OK
value(); // OK
value.foo.bar = 10; // OKAt 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
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
let value: unknown = "hello";
if (typeof value === "string") {
console.log(value.toUpperCase()); // ✅ Allowed: TypeScript knows value is a string
}B. Using instanceof checks
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:
let value: unknown = getApiData();
const strValue = value as string;
console.log(strValue.trim()); // ✅ Allowed4. Key Contrast Summary
| Action / Capability | any | unknown |
|---|---|---|
| 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
unknownby 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
anyunless migrating legacy JavaScript or writing complex generic libraries where type safety is managed via other assertions. - Top Type Behavior: Both
anyandunknownare top types (all values are assignable to them), butunknowncannot be assigned to anything else without narrowing.