TS never / void
never and void both describe "no useful return value" — but they mean very different things.
void — "returns nothing"
TS
function log(msg: string): void {
console.log(msg);
// no return statement, or return; with no value
}
const result = log('hi'); // result is undefined
A function that produces a side effect and doesn't give back a value. The caller usually ignores what comes back.
never — "doesn't return at all"
TS
function fail(msg: string): never {
throw new Error(msg);
}
function infiniteLoop(): never {
while (true) {}
}
The function either throws or runs forever. Code after a call to a never-returning function is unreachable.
never as the bottom type
never is the empty type — it has zero possible values. It's a subtype of everything, which makes it useful for exhaustiveness checks:
TS
type Shape = { kind: 'circle' } | { kind: 'rect' };
function area(s: Shape): number {
switch (s.kind) {
case 'circle': return 0;
case 'rect': return 0;
default: {
const exhaustive: never = s;
// If a new variant is ever added, this errors at compile time.
throw new Error('unhandled');
}
}
}
Why "Promise<void>" not "Promise<never>"
TS
async function save(): Promise<void> {
// The promise resolves, just with no useful value.
}
The function returns — there's nothing to do with the result. That's void. never would mean the promise never resolves.
Tip: Use
never in conditional types to "discard" branches. type Extract<T, U> = T extends U ? T : never — that's how a lot of the utility types are built.Example
Example
function fail(msg: string): never {
throw new Error(msg);
}
function log(msg: string): void {
console.log(msg); // returns nothing
}
log('side effect only');
Try it Yourself »
Exercise
Return type of a function that always throws.
function fail():
{ throw new Error(); }
Five letters.
Discussion
Loading…