This is one of the trickiest but most important parts of TypeScript — the special types: any, unknown, never, and void. These are not primitives, but they give TypeScript extra power for handling real-world scenarios in React, Angular, Vue, and Node/Express apps.
Let’s dive into a clear, structured explanation 👇
Special Types in TypeScript — any, unknown, never, void
TypeScript provides special types that are not used every day but are essential for handling edge cases in modern apps.
any→ disables type safety (use with caution).unknown→ safer alternative toany.never→ represents values that never occur.void→ represents functions that don’t return anything.
1. any
What it is
The escape hatch of TypeScript. It tells the compiler:
“Don’t check this. Trust me, I know what I’m doing.”
Any is a friend for beginners in TypeScript because it turns off any type checking, but Any is the an enemy for real commercial projects because it creates weak places in it security and creates possibility to avoid type checking.
In most of real commercial projects using Any in the code of TypeScript is strictly prohibited.
Example
let value: any;
value = "Hello";
value = 42;
value = { key: "value" };
When to use
- Migrating a JavaScript project to TypeScript gradually.
- When working with 3rd-party libraries without type definitions.
- Quick prototyping when exact types are unknown.
Framework Examples
- React: When props come from dynamic data and you haven’t typed them yet.
- Angular/Vue: When working with legacy services with mixed data.
- Express/Node: Accessing
req.bodywithout a schema.
// Express example (bad but sometimes necessary)
app.post("/user", (req, res) => {
const data: any = req.body; // no validation
console.log(data.randomProperty); // compiler doesn’t complain
});
⚠️ Avoid in production — it removes all type safety.
2. unknown
What it is
A safer version of any.
You can assign anything to unknown, but you must check its type before using it.
Example
let input: unknown = "Hello";
if (typeof input === "string") {
console.log(input.toUpperCase()); // ✅ Safe
}
When to use
- When you know a value can be anything, but want to enforce type checking before use.
- Safer handling of user input, API responses, or external libraries.
Framework Examples
- React: Handling data from APIs before mapping into props.
- Angular/Vue: Parsing dynamic JSON responses.
- Express/Node: Validating
req.bodywith runtime checks.
// Express with unknown
app.post("/login", (req, res) => {
const body: unknown = req.body;
if (typeof body === "object" && body !== null && "username" in body) {
const { username } = body as { username: string };
res.send(`Hello, ${username}`);
} else {
res.status(400).send("Invalid request");
}
});
✅ Encourages type-safe validation.
3. never
What it is
Represents values that never happen.
A function that throws an error or runs forever has return type never.
Example
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
When to use
- For exhaustive type checks in switch/case statements.
- For error handling functions that never return.
Framework Examples
- React: Ensuring exhaustive props handling.
- Angular/Vue: State management where all cases must be covered.
- Node/Express: Handling impossible conditions in middleware.
// Exhaustive check example (React reducer)
type Action = { type: "ADD" } | { type: "REMOVE" };
function reducer(state: number, action: Action): number {
switch (action.type) {
case "ADD": return state + 1;
case "REMOVE": return state - 1;
default:
const _exhaustive: never = action; // compile-time error if new action added
return state;
}
}
✅ Helps ensure no forgotten cases.
4. void
What it is
Represents a function that does not return a value.
Often used for functions that perform side effects.
Example
function logMessage(msg: string): void {
console.log(msg);
}
When to use
- Event handlers.
- Logging, notifications, DOM updates.
- As a return type when only side effects are expected.
Framework Examples
- React:
onClickhandlers. - Angular/Vue: Lifecycle hooks that don’t return values.
- Node/Express: Middleware that only sends a response (no return).
// React
const Button = () => {
const handleClick = (): void => {
console.log("Clicked!");
};
return <button onClick={handleClick}>Click me</button>;
};
✅ Makes intent clear: “This function does work, but doesn’t return anything.”
Quick Comparison Table
| Type | Meaning | Assignability | Example Use Case |
|---|---|---|---|
| any | Disable type checking | Can assign to anything | Quick prototyping, legacy code |
| unknown | Type-safe any | Must check before use | API responses, user input |
| never | Value never occurs | No value can be assigned | Error functions, exhaustive checks |
| void | No return value | Only undefined or nothing | Event handlers, logging |
Conclusion
- Use
anyonly as a last resort. - Prefer
unknownwhen type is not known upfront. - Use
neverfor error functions and exhaustive checks. - Use
voidfor functions that don’t return anything (like event handlers).
Together, these special types give you more precise control over how TypeScript enforces correctness across React, Angular, Vue, and Node/Express apps.