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:

TS any.ts
let data: any = "hello";

data = 42;
data = { nested: true };

console.log(data.nested);
console.log(data.this.does.not.exist);
Output
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:

TS unknown.ts
let input: unknown = JSON.parse('{"name":"Kai"}');

console.log(input.name);
tsc output
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:

TS unknown-narrow.ts
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));
Output
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:

TS void.ts
function logVisit(page: string): void {
  console.log(`Visited ${page}`);
}

logVisit("/pricing");
Output
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

TS never-fn.ts
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"));
Output
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.

TS never-branch.ts
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));
Output
text number

Quick comparison

TypeAccepts any value?Can you use it freely?Typical use
anyYesYes — uncheckedEscape hatch, migration
unknownYesNo — narrow firstUntrusted input, caught errors
void——Functions with no return value
neverNo values at all—Throwing functions, exhaustive checks

Try it yourself

Try it yourself
Console output