Some TypeScript types are easy to confuse. Understanding their boundaries is essential for writing safer code.
any: Turning Off Type Checking
any means any type. It is convenient, but it bypasses type checking.
let value: any = 42;
value = "hello";
value.toFixed();More dangerously, any can be assigned to any other type.
let input: any = 9;
let name: string = input; // compiles, but unsafeUse any sparingly, mainly when migrating legacy code or dealing with truly unknown external data.
unknown: A Safer Unknown Value
unknown also represents an uncertain value, but it requires narrowing before use.
let value: unknown = "hello";
if (typeof value === "string") {
console.log(value.toUpperCase());
}If you mean "I do not know what this is yet", prefer unknown over any.
void: No Meaningful Return Value
void is commonly used for functions whose return value should not be used.
function log(message: string): void {
console.log(message);
}never: No Normal Completion
never means a function never returns normally, often because it throws or loops forever.
function fail(message: string): never {
throw new Error(message);
}It is also useful for exhaustive checks.
type Status = "success" | "error";
function handle(status: Status) {
switch (status) {
case "success":
return "ok";
case "error":
return "failed";
default:
const exhaustive: never = status;
return exhaustive;
}
}null and undefined
undefined usually means a value has not been assigned. null usually means intentionally empty.
With strictNullChecks, they cannot be assigned freely to other types.
let age: number | null | undefined;
age = 18;
age = null;
age = undefined;Strict null checking helps prevent many null-reference bugs.