unknown vs any
1. What unknown does
unknownis a safe alternative toany. It says: "I don't know what this value is, so you must prove its type before using it."
Example:
let value: unknown = "hello";
value.toUpperCase(); // Error: Object is of type 'unknown'
if (typeof value === "string") {
value.toUpperCase(); // OK, the type is proven
}Unlike any, TypeScript does not let you do anything
until you narrow the type.
That is what makes unknown safe by default.
2. Why unknown is safer than any
| Behavior | any | unknown |
|---|---|---|
| Can call methods without checking | Yes | No |
| Can be assigned to other types | Without restriction | Only after a check |
| IDE suggests properties | No | No (until checked) |
| Requires type narrowing | No | Yes |
| Can cause runtime errors | Often | Only if you bypass the checks |
Example:
let a: any = "hello";
let u: unknown = "hello";
a.foo(); // TS lets it through → fails at runtime
u.foo(); // TS does not allow it → safe3. Why unknown can still be used badly
Although unknown is safer, it all depends on what you do with it.
If you forcibly "break" the typing, unknown stops being safe.
Mistake 1: Forced casting with as
let data: unknown = "Hello";
const num = data as number; // forced cast
console.log(num.toFixed(2)); // runtime errorThe cast (as number) bypasses all of TS's checks.
In other words, you are back to the behavior of any.
Takeaway:
unknown is safe as long as you do not force TS to "take your word for it."
Mistake 2: Spreading unknown too widely
If you return unknown from functions or store it in data structures,
the type system loses context.
Example:
function parseJSON(str: string): unknown {
return JSON.parse(str);
}
const result = parseJSON('{"id":1,"name":"Alex"}');
// result: unknown
console.log(result.name); // error, until you check itThis is safe, but inconvenient: you are forced to narrow types by hand everywhere. If there are many such values, this leads to type chaos.
Mistake 3: Overly generic function types
If everything in an API function is declared as unknown,
you lose the benefit of typing: the IDE no longer knows what the function returns.
function getUser(): unknown {
return { name: "Alex", age: 30 };
}
const user = getUser();
user.name; // Error: TS does not know there is an object thereThe code is safe but useless: TS protects you from errors but does not help you develop.
Mistake 4: Assigning unknown without narrowing
let data: unknown = 42;
let str: string = data; // Error: Type 'unknown' is not assignable to type 'string'It is good that TypeScript catches this,
but if you write as string, the logic still breaks:
let str = data as string;
console.log(str.toUpperCase()); // runtime error4. How to use unknown correctly
Use unknown as a safety barrier,
at the boundaries with external data that you cannot trust (API, JSON, user input).
Example:
function parse<T>(json: string): T {
const data: unknown = JSON.parse(json);
if (isUser(data)) {
return data; // TS is now sure
}
throw new Error("Invalid user data");
}Here:
unknown→ a safe startisUser()→ a type guardT→ we return a typed value
5. When unknown is better than any, and when it is not
| Situation | Better with unknown | Better with any |
|---|---|---|
| Receiving data from an API | Yes | No |
| Quick debugging or temporary code | Possible, but clunky | Yes (temporarily) |
| Writing generic functions | Yes (narrow the type later) | No |
| Legacy code with no time for strict checks | Inconvenient | Temporarily acceptable |
| Public libraries | Yes (external input is unknown) | No |
6. A correct example with checks
function isUser(value: unknown): value is { id: number; name: string } {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value
);
}
const data: unknown = JSON.parse('{"id":1,"name":"Alex"}');
if (isUser(data)) {
console.log(data.name.toUpperCase()); // safe
} else {
console.error("Invalid user");
}Here unknown does its job:
it protects against the wrong type until you prove otherwise.
7. The fundamental difference in philosophy
any | unknown | |
|---|---|---|
| Philosophy | "I know what I'm doing" | "I don't know what this is yet" |
| Safety | absent | maximum |
| Use case | temporary solutions, legacy | external data, APIs, dynamic content |
| Type checking | disabled | mandatory |
| Breaks the type contract | easily | only through as |
Summary
| Question | Answer |
|---|---|
Why is unknown safer? | It forces you to check the type before using it. |
| Why can it be dangerous? | If you bypass the checks with as or use it too broadly, the point of typing is lost. |
| Where is it appropriate? | At application boundaries: parsing JSON, user input, unpredictable APIs. |
| The main idea | unknown is a "safe unknown." You cannot use the value until you prove it is the right type. |
Just remember:
any- "I know better than TypeScript."unknown- "TypeScript, help me make sure."But if you "trick" the compiler yourself (with
as), thenunknownstops being safe and becomes plainanyin disguise.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.