Skip to content

Special Types in TypeScript

flowchart TB
Unk[unknown<br/>Top type — every type fits here] --> Obj[object<br/>Non-primitive types: functions, arrays, classes]
Obj --> Func[Function]
Obj --> Arr[Array]
Obj --> Custom[Interfaces & Classes]
Obj --> Prim[string | number | boolean | bigint | symbol]
Prim --> Never[never<br/>Bottom type — nothing fits here]
Any[any<br/>⚠️ Bypasses the entire hierarchy] -.- Unk
Any -.- Never
style Unk fill:#7c3aed,color:#fff
style Any fill:#ef4444,color:#fff
style Obj fill:#3b82f6,color:#fff
style Func fill:#059669,color:#fff
style Arr fill:#059669,color:#fff
style Custom fill:#059669,color:#fff
style Prim fill:#f59e0b,color:#fff
style Never fill:#10b981,color:#fff

Analogy: unknown is the ceiling — every type fits under it. never is the floor — nothing goes below it. any is a trapdoor that bypasses the whole hierarchy.

let value: any = 42;
value = "Hello";
value = true;
value.doSomething(); // No error — but likely runtime crash
// When any is dangerous:
const users: any[] = [{ id: 1 }, { id: 2 }];
users[0].name.toUpperCase(); // Runtime error! name is undefined
let value: unknown = 42;
value = "Hello";
// Cannot use without narrowing:
// value.toUpperCase(); // ❌ Error
if (typeof value === "string") {
value.toUpperCase(); // OK — narrowed
}
// Parse JSON safely
function safeParse(json: string): unknown {
return JSON.parse(json);
}
const data = safeParse('{"name":"Alice"}');
if (data && typeof data === "object" && "name" in data) {
console.log((data as { name: string }).name);
}
function log(message: string): void {
console.log(message);
}
const result = log("test"); // result is void
// void vs undefined:
function returnsUndefined(): undefined { return undefined; }
function returnsVoid(): void { }
// void allows both undefined and null returns
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
// Exhaustive checking
type Shape = Circle | Square;
function getArea(shape: Shape): number {
switch (shape.kind) {
case "circle": return Math.PI * shape.radius ** 2;
case "square": return shape.side * shape.side;
default: return assertNever(shape);
}
}
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`);
}
let nothing: null = null;
let notDefined: undefined = undefined;
// Strict null checks (recommended)
// tsconfig: "strictNullChecks": true
function greet(name: string | null): string {
if (name === null) return "Hello, Guest";
return `Hello, ${name}`;
}
// Optional chaining with null
const user = { profile: { name: "Alice" } };
const name = user?.profile?.name; // string | undefined

Easy: What’s the difference between any and unknown?

Medium: When does never occur in TypeScript?

Hard: How does void differ from undefined?