The void
operator has historically had a few use cases:
- Used with
<a href="javascript:void(0)">
to implement dynamic buttons, but this is a poor and dated practice - Used to access the primitive
undefined
value in the bad old days prior to ES5 when it was possible to overwrite the identifierundefined
- Used to save a few characters and shorten
undefined
to justvoid 0
; this is still used by minifiers
None of these use cases are particularly relevant to modern JavaScript, except for a new case that's been introduced with arrow functions in ES6:
ES6 arrow function expressions allow omitting the braces from the function body to make code more terse, but it creates an ambiguity about when the return value is or isn't intended to be used, because the function might be intended just for side effects:
// omitting braces
const id = x => x;
// function called just for side effects
const log = x => console.log(x);
The Console API is widely familiar, so this particular example isn't ambiguous, but it illustrates the principle.
Intentional void arrow functions can be made explicit by adding braces, but this makes them less terse:
const log = x => {
console.log(x);
}
The function could still be formatted in a single line, but automatic formatting tools like Prettier will usually add line breaks, and the intention to not return a value is not as clear as when using the void
operator:
const log = x => void console.log(x);
The most noticeable benefit of using void
like this is reducing the line count; especially in programming styles like CPS that rely on void callbacks often.
Type systems and void type
Many type systems, including TypeScript's, have the concept of a void type, which makes the use of the void
operator for non-value-returning functions complementary and more recognizable.
React useEffect
hook
A common practical use case for void
is with the useEffect
hook in React:
useEffect(() => void (document.title = 'example'));
It's a particularly salient example because the useEffect
hook can use its callback's return value for cleaning up the effect, so accidentally returning a function could be a runtime bug.
There's an additional but less important use case for the void
operator with async immediately-invoked function expressions (IIFES). Traditionally IIFES were used to implement modular scopes, since JS didn't have block scope or actual modules, but modern JS has both, so IIFES are largely not relevant except for one case: using theawait
or for-await-of
syntax at the top level of modules:
void (async () => {
await fetch(something);
})();
This is a popular enough use case that there exists a stage 3 proposal for it. Parenthesis are still required around the function expression due to precedence rules, but using void
solves the problem that leading parenthesis don't work with ASI (more specifically, it breaks without explicit semicolon line terminators).
Style guides and no-void
Popular style guides like Airbnb's and Standard JS use the no-void
ESLint rule to prohibit using the void
operator, but it's arguably an oversight and should be overridden by users.
I opened an GH issue based on the original one linked to by this gist to adjust
no-void
to support the use-cases described here, which the ESLint team are currently evaluating. Here's the GH issue to check out if folks want to weigh in or +1 to show that there's interest in having the change made :)