Skip to content
Happy Programming Guide
Start learning
JavaScript

The JavaScript Double Exclamation Mark, Explained

What the double exclamation mark actually does in JavaScript, why it is not an operator, when it is genuinely useful, and when Boolean() reads better.

Servers mounted in a data centre rack

The double exclamation mark in JavaScript is not a special operator. It is the ! operator applied twice: the first negates the value into a boolean, the second negates it back. The net effect is to convert anything into its true-or-false equivalent. Applied to a non-empty string it gives true; applied to zero it gives false.

How it works#

JavaScript
const value = "hello";

console.log(!value);    // false - negated once, now a boolean
console.log(!!value);   // true  - negated again, back to the original sense

The first ! does the real work. It forces the value to a boolean and flips it. The second simply flips it back, leaving you with a genuine boolean carrying the original truthiness.

JavaScript
!!"hello"     // true
!!""          // false
!!42          // true
!!0           // false
!![]          // true  - an empty array is truthy
!!{}          // true  - so is an empty object
!!null        // false
!!undefined   // false
!!NaN         // false

The falsy values#

There are exactly eight, and everything else is truthy:

JavaScript
false
0
-0
0n          // BigInt zero
""          // empty string
null
undefined
NaN

Two catch people out constantly: an empty array and an empty object are both truthy. So is the string "0" and the string "false".

JavaScript
if ([]) console.log("runs");        // yes
if ("0") console.log("runs");       // yes
if (0) console.log("does not");     // no

Where it is actually useful#

1. Returning a boolean from a function.

JavaScript
// Returns the string, or undefined
function hasEmail(user) {
  return user.email;
}

// Returns true or false
function hasEmail(user) {
  return !!user.email;
}

The second version is honest about what it returns, which matters when the result is stored, serialised or compared with ===.

2. Conditional rendering in JSX. This is where it earns its keep:

JavaScript
// Renders a literal 0 when the array is empty
{items.length && <List items={items} />}

// Renders nothing
{!!items.length && <List items={items} />}

React renders the number 0 but ignores false. Since && returns the left operand when it is falsy, an empty array produces a stray zero on the page. Converting to a boolean first prevents it. Writing items.length > 0 works equally well and is arguably clearer.

3. Filtering out falsy values.

JavaScript
const values = [1, null, "a", undefined, 0, "b", ""];

const truthy = values.filter(Boolean);       // [1, "a", "b"]
const same = values.filter(v => !!v);        // identical

filter(Boolean) is the idiomatic form. It works because Boolean is a function that does exactly this conversion.

4. Counting.

JavaScript
const filledCount = fields.reduce((total, f) => total + !!f.value, 0);

Booleans convert to 1 and 0 in arithmetic, so this counts the non-empty fields.

Where it is noise#

JavaScript
// Unnecessary - if already coerces
if (!!user) { }
if (user) { }

// Unnecessary - the ternary already branches on truthiness
const flag = !!value ? "yes" : "no";
const flag = value ? "yes" : "no";

// Unnecessary - comparison already returns a boolean
return !!(count > 0);
return count > 0;

Anywhere JavaScript already coerces to a boolean — if, while, the ternary, &&, ||, a loop condition — the conversion adds nothing.

Double negation or Boolean()#

JavaScript
const a = !!value;
const b = Boolean(value);

Identical results. The trade-off is familiarity against explicitness: Boolean(value) reads clearly to anyone, while the double negation is shorter and idiomatic among people who already know it. Boolean also works directly as a callback, which the operator form cannot.

Many style guides require Boolean() for exactly this reason. Whichever you choose, be consistent.

JavaScript
// || returns the first truthy value
const name = input || "Anonymous";      // 0 and "" get replaced too

// ?? returns the right side only for null and undefined
const count = input ?? 0;               // 0 and "" are preserved

// ! negates once
if (!user) return;

// !! converts without negating
const hasUser = !!user;

Use ?? for defaults. That single habit removes a whole class of bug where a legitimate 0 or empty string gets silently replaced.

The comparison trap#

JavaScript
console.log([] == false);      // true  - loose equality converts both
console.log(!![]);             // true  - an empty array is truthy

These look contradictory and are not. Loose equality converts the array to an empty string and then to zero, which equals false. Truthiness does no such conversion. This is one of several reasons to use === and never ==.

Questions people ask#

Is double negation slower than Boolean()?

No, to any degree you could measure. Choose on readability.

Does it work in TypeScript?

Yes, and it narrows types usefully: the result is typed boolean, and inside the condition TypeScript knows the value is not null or undefined.

Why does an empty array evaluate as true?

Because every object is truthy in JavaScript, and an array is an object. To test for emptiness, check items.length > 0.

Is there a triple exclamation mark?

It is valid and equivalent to a single !, since each pair cancels out. Nobody writes it deliberately; if you see one it is a typo.

Where to go next#

One-line conditionals in JavaScript, and when to avoid themRead next

Keep reading

JavaScript

Introduction to ES6 and Beyond

The JavaScript features added since 2015 that changed how the language is written: let and const, arrow functions, destructuring, modules, async/await and…

5 min read

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *