Difficulty: Intermediate
TypeScript has three special types that occupy important positions in the type system: `any`, `unknown`, and `never`. Understanding the differences between them is crucial for writing safe TypeScript and is a common interview topic. Additionally, `void` plays a specific role for functions that don't return a value. Together, these types form the boundary conditions of the type system.
The `any` type is an escape hatch that completely disables type checking. A value of type `any` can be assigned to any other type, and any type can be assigned to `any`. You can call any method on it, access any property, and perform any operation without TypeScript complaining. While useful during migration from JavaScript, `any` should be avoided in production code because it silently propagates through your codebase - a single `any` can infect related variables and functions, creating blind spots in type safety.
The `unknown` type is the type-safe counterpart to `any`. Like `any`, it can hold any value - but unlike `any`, you cannot do anything with an `unknown` value until you narrow its type through type guards. You must use `typeof`, `instanceof`, or other checks before accessing properties or calling methods on an `unknown` value. This forces you to validate the type at runtime before using it, making `unknown` the correct choice for values whose type you genuinely don't know, such as parsed JSON, user input, or data from external APIs.
The `never` type represents values that can never occur. It's the return type of functions that always throw errors or have infinite loops, and it appears in exhaustive type narrowing when all possibilities have been handled. In type theory, `never` is the "bottom type" - it's assignable to every other type but no type is assignable to `never`. The `void` type is different: it represents the absence of a return value in functions. A `void` function can return `undefined` implicitly but cannot return any other value.
// any: no type safety at all
let dangerous: any = "hello";
dangerous = 42;
dangerous = { foo: "bar" };
// No errors - but also no help from TypeScript
// unknown: must narrow before using
let safe: unknown = "hello";
// safe.toUpperCase(); // Error: Object is of type 'unknown'
// Narrow with typeof before using
if (typeof safe === "string") {
console.log(safe.toUpperCase()); // OK after narrowing
}
if (typeof safe === "number") {
console.log(safe.toFixed(2));
} else {
console.log("Not a number");
}
With `any`, TypeScript allows everything - no errors, no safety. With `unknown`, you must prove the type before using the value. Always prefer `unknown` over `any` when the type is genuinely not known.
// never: function that always throws
function throwError(message: string): never {
throw new Error(message);
}
// never: exhaustive type checking
type Shape = "circle" | "square" | "triangle";
function getArea(shape: Shape): string {
switch (shape) {
case "circle": return "pi * r^2";
case "square": return "side^2";
case "triangle": return "0.5 * base * height";
default:
// If all cases are handled, 'shape' is type 'never' here
const exhaustiveCheck: never = shape;
return exhaustiveCheck;
}
}
console.log(getArea("circle"));
console.log(getArea("triangle"));
The `never` type in the default branch ensures exhaustive checking. If you add a new Shape variant without handling it in the switch, TypeScript will show a compile error at the `never` assignment.
// void: function that doesn't return a meaningful value
function logMessage(msg: string): void {
console.log(msg);
// implicitly returns undefined
}
// undefined: explicit undefined value
function findItem(items: string[], target: string): string | undefined {
return items.find(item => item === target);
}
logMessage("Hello from void function");
const result = findItem(["a", "b", "c"], "b");
console.log(result !== undefined ? result : "not found");
const missing = findItem(["a", "b"], "z");
console.log(missing !== undefined ? missing : "not found");
void means a function doesn't return anything useful. undefined is an actual value that can be returned. never means the function never completes (throws or loops forever).
any type, unknown type, never type, void type, Top and bottom types