What is any vs unknown in TypeScript?
Understand the difference between any and unknown in TypeScript, why unknown is safer, and how to narrow unknown values with type guards, with examples.
Expected Interview Answer
`any` disables type checking entirely, letting you call any method or access any property on the value with no compiler complaints, while `unknown` also accepts any value but forces you to narrow its type before you can do anything with it, preserving type safety.
Both types can hold values of any type, so `let x: any = 5` and `let y: unknown = 5` are both legal starting points. The difference shows up on use: `x.toUpperCase()` compiles even though `x` is a number and will crash at runtime, whereas `y.toUpperCase()` is a compile-time error until you narrow `y` with a type guard like `typeof y === 'string'`. `any` essentially opts a value out of the type system, silently propagating unsafety to everything it touches, while `unknown` is the type-safe counterpart designed for genuinely unknown external data like JSON responses. In strict mode, prefer `unknown` at API boundaries and reserve `any` for rare escape hatches.
- `unknown` forces explicit narrowing before any operation is allowed
- `any` silently disables checking, which spreads unsafety through your code
- `unknown` is the safer default for parsing untrusted external data (JSON, API responses)
- Narrowing `unknown` with `typeof`/`instanceof` restores full IntelliSense
- Using `unknown` instead of `any` catches bugs at compile time instead of runtime
AI Mentor Explanation
Treating a value as `any` is like letting any spectator walk onto the pitch and bowl without checking their credentials, trusting blindly that it will go fine. Treating it as `unknown` is like stopping that same person at the boundary rope and requiring them to show a valid player accreditation card before they're allowed anywhere near the stumps.
Step-by-Step Explanation
Step 1
Declare with any
`let x: any = fetchData();` — the compiler permits any operation on `x` with no further checks.
Step 2
Declare with unknown
`let y: unknown = fetchData();` — the same assignment is allowed, but using `y` directly is blocked.
Step 3
Attempt direct use
`y.toUpperCase()` fails to compile: 'Object is of type unknown', while the identical call on `x: any` compiles silently.
Step 4
Narrow with a type guard
`if (typeof y === 'string') { y.toUpperCase(); }` — inside the guard, TypeScript now treats `y` as `string`.
Step 5
Choose unknown at boundaries
Use `unknown` for `JSON.parse()` results or third-party API responses, then validate/narrow before trusting the shape.
What Interviewer Expects
- Explains `unknown` requires narrowing before use, `any` does not
- Can demonstrate narrowing with `typeof` or `instanceof`
- Knows both accept any value on assignment — the difference is on use
- Recommends `unknown` over `any` for untrusted external data
- Understands `any` silently propagates unsafety through the codebase
Common Mistakes
- Using `any` as a lazy fix whenever a type error appears
- Believing `unknown` and `any` behave identically
- Forgetting to narrow `unknown` before calling a method on it
- Casting `unknown` directly with `as` instead of using a proper type guard
Best Answer (HR Friendly)
“`any` turns off type checking completely, which is risky because mistakes only show up when the program actually runs. `unknown` is a safer alternative that still lets you hold any kind of value, but TypeScript makes you verify what it actually is before you use it, catching errors earlier.”
Code Example
let a: any = 5;
a.toUpperCase(); // compiles, crashes at runtime: a.toUpperCase is not a function
let u: unknown = 5;
// u.toUpperCase(); // Error: Object is of type 'unknown'
if (typeof u === 'string') {
u.toUpperCase(); // OK, narrowed to string inside this block
}Follow-up Questions
- How do you safely narrow an `unknown` value before using it?
- Why is `unknown` considered the type-safe counterpart to `any`?
- In what real scenario would you legitimately still need `any`?
- How does `unknown` interact with union types during narrowing?
- What does the TypeScript compiler flag do (`noImplicitAny`) and how does it relate?
MCQ Practice
1. What happens when you call `.toUpperCase()` directly on a variable typed `unknown`?
TypeScript blocks any operation on an `unknown` value at compile time until you've narrowed it with a type guard.
2. What happens when you call `.toUpperCase()` on a variable typed `any` holding a number?
`any` disables type checking, so the call compiles, but calling a nonexistent method on a number crashes at runtime.
3. Which type is recommended for handling untrusted data like a JSON API response?
`unknown` forces you to validate and narrow the shape of external data before using it, making it the safer choice.
Flash Cards
Can you call a method directly on an `any` value? — Yes — `any` disables all type checking, so it compiles even if it crashes at runtime.
Can you call a method directly on an `unknown` value? — No — you must narrow it first (e.g. with `typeof`) before TypeScript allows any operation.
Which type is safer for untrusted external data? — `unknown` — it forces validation before use, unlike `any`.
How do you narrow an `unknown` value to `string`? — Use a type guard like `if (typeof value === 'string') { ... }`.