any, unknown, never & void
Four special types sit at the edges of TypeScript's type system. any switches checking off, unknown means "could be anything, so prove it first", void marks functions that return nothing useful, and never describes values that can't exist.
any: the off switch
A value typed any can be used in any way at all, and TypeScript won't complain:
let data: any = "hello"; data = 42; data = { nested: true }; console.log(data.nested); console.log(data.this.does.not.exist);
true
That program compiles without a single error, then crashes on the last line (with TypeError: Cannot read properties of undefined). any also spreads: anything you read from an any value is any too, so one careless any can quietly disable checking across a whole chain of code.
Legitimate uses are rare: gradually migrating old JavaScript, or briefly working around a library with broken types. Strict mode — on by default since TypeScript 6.0 (lesson 38) — stops TypeScript from inferring any silently, so it only appears where someone wrote it on purpose.
unknown: the safe alternative
unknown also accepts any value, but you can't do anything with it until you've checked what it is:
let input: unknown = JSON.parse('{"name":"Kai"}'); console.log(input.name);
error TS18046: 'input' is of type 'unknown'.
To use it, narrow it down with a runtime check. Inside each branch, TypeScript knows the more specific type:
function describe(value: unknown): string { if (typeof value === "string") { return `a string of length ${value.length}`; } if (typeof value === "number") { return `the number ${value.toFixed(1)}`; } if (Array.isArray(value)) { return `an array with ${value.length} items`; } return "something else"; } console.log(describe("hey")); console.log(describe(3)); console.log(describe([1, 2])); console.log(describe(null));
a string of length 3 the number 3.0 an array with 2 items something else
Use unknown for anything whose shape you don't control: parsed JSON, caught errors, messages from other windows. It forces the validation you should be doing anyway.
void: no useful return value
void is the return type of a function that doesn't return anything meaningful:
function logVisit(page: string): void { console.log(`Visited ${page}`); } logVisit("/pricing");
Visited /pricing
If you leave the return type off, TypeScript infers void for you. Trying to return "done" from a function declared as void is an error.
never: a value that can't exist
never is the type of something that never happens. Two common places it appears:
Functions that never finish
function fail(message: string): never { throw new Error(message); } function parsePort(raw: string): number { const port = Number(raw); if (Number.isNaN(port)) { fail(`Not a number: ${raw}`); } return port; } console.log(parsePort("8080"));
8080
A function that always throws (or loops forever) can never return a value, so its return type is never. That's different from void, which does return — just without a useful value.
Impossible branches
After every possibility has been handled, whatever is left over has type never. Lesson 23 uses this to make the compiler warn you when you forget to handle a case.
function label(value: string | number) { if (typeof value === "string") return "text"; if (typeof value === "number") return "number"; const leftover: never = value; return leftover; } console.log(label("a"), label(1));
text number
Quick comparison
| Type | Accepts any value? | Can you use it freely? | Typical use |
|---|---|---|---|
any | Yes | Yes — unchecked | Escape hatch, migration |
unknown | Yes | No — narrow first | Untrusted input, caught errors |
void | — | — | Functions with no return value |
never | No values at all | — | Throwing functions, exhaustive checks |