any, unknown and never
Three special types sit at the edges of TypeScript's type system. any and unknown both accept every value, yet one is dangerous and the other is safe. never accepts no value at all, and is surprisingly useful. Knowing which is which keeps your checks honest.
The rule
any trusts everything, unknown trusts nothing yet, never has no values.
any — accepts every value and allows every operation. Checking is switched off:
let saved: any = JSON.parse(text);
saved.tasks.forEach((t: any) => t.titel.trim()); // compiles, may crash
const n: number = saved; // also compilesany also leaks: assign it to a typed variable and the compiler believes you.
unknown — also accepts every value, but allows nothing until you check what it is:
let data: unknown = JSON.parse(text);
data.tasks; // error: data is unknown
if (typeof data === "object" && data !== null && "tasks" in data) {
// data is now known to be an object with a tasks property
}unknown is the right type for things that come from outside — parsed JSON, user input, caught errors (catch (e) is unknown in strict mode). You pay for safety with a check, which is exactly the point.
never — the type with no values. You meet it in three places:
- A function that never finishes normally, such as one that always throws:
function fail(msg: string): never { throw new Error(msg); } - Impossible types, like
string & number. - What is left after narrowing has ruled out every possibility — which gives an exhaustive check:
type Status = "todo" | "doing" | "done";
function label(s: Status): string {
switch (s) {
case "todo": return "To do";
case "doing": return "In progress";
case "done": return "Done";
default:
const unreachable: never = s;
return unreachable;
}
}Every case is handled, so in default the type of s is never. Add "blocked" to Status and forget a case: now s could be "blocked", which cannot be assigned to never, and the compiler points straight at the missing case.
The shortcut
Ask "How much do I know about this value?"
- Nothing yet, it comes from outside →
unknown, then narrow. - I am giving up on checking →
any, and only as a last resort. - This cannot happen →
never.
Parse
const raw: unknown = JSON.parse(localStorage.getItem("tasks") ?? "[]");
Drills
Answer fast — trust the rule.
A value is typed unknown. What can you do with it before any check?
Which type is safest for the result of JSON.parse?
What is the return type of a function that always throws an error?
In the exhaustive switch over Status, what happens if you add "blocked" to Status but no new case?
Why is any considered more dangerous than unknown?
Remember
- any trusts everything, unknown trusts nothing yet, never has no values.
- Ask how much you know: nothing yet is unknown; impossible is never.
- Trap:
anycompiles typos and leaks into typed code; reach forunknownfirst.
