unknown vs any
1. What unknown does
unknownis a safe alternative toany. It says: "I do not 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 allow doing anything
until you refine (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 a check | Yes | No |
| Can be assigned to other types | No restrictions | Only after a check |
| The IDE suggests properties | No | No (until checked) |
| Requires type narrowing | No | Yes |
| Can cause runtime errors | Often | Only if the checks are bypassed |
Example:
let a: any = "hello";
let u: unknown = "hello";
a.foo(); // TS lets it through -> crashes at runtime
u.foo(); // TS does not allow it -> safe3. Why unknown can still be used badly
Although unknown is safer, everything 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; // a forced cast
console.log(num.toFixed(2)); // a runtime errorThe cast (as number) bypasses all of TS's checks.
That is, you have returned to the behavior of any.
Conclusion:
unknown is safe as long as you do not force TS to "take your word for it".
Mistake 2: Spreading unknown 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); // an error, until you check itThis is safe, but inconvenient - you are forced to manually narrow the type everywhere. If there are many such values, this leads to typing chaos.
Mistake 3: Overly generic function types
If everything in an API function is declared as unknown,
you lose the usefulness 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 it is an objectThe code is safe, but useless: TS protects against mistakes 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()); // a runtime error4. How to use unknown correctly
Use unknown as a safety barrier -
at the boundaries with external data, where you cannot trust the types (an 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 confident
}
throw new Error("Invalid user data");
}Here:
unknownis the safe starting pointisUser()is the type guardTis the typed value we return
5. When unknown is better than any, and when it is not
| Situation | unknown is better | any is better |
|---|---|---|
| Receiving data from an API | Yes | No |
| Quick debugging or temporary code | Possible, but cumbersome | Yes (temporarily) |
| Writing universal 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 do not yet know what this is" |
| Safety | absent | maximal |
| Use case | temporary solutions, legacy code | external data, APIs, dynamism |
| 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 the boundaries of an application: 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 type you need. |
Just remember:
anysays "I know better than TypeScript".unknownsays "TypeScript, help me make sure".But if you "trick" the compiler yourself (via
as), thenunknownstops being safe and becomes a regularanyin disguise.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.