Content:
Strictly speaking, the title of this article is incorrect. Despite looking like one, !!
is not itself an operator. It’s actually just the !
(negation) operator, repeated twice.
With that said, you might be thinking, what’s the point of that? If you negate something, then negate it again, aren’t we back with what we started with?
And you’d be right to think that. But also wrong. Very wrong. Let’s see why.
const x = 10;
console.log(!!x);
A very simple example to start. Easy, right? 10 -> -10 -> 10. Well, try it out, and see what happens.
// Result
true
Kudos if you realised the result would be true
.
So, what’s going on here? What exactly is this strange looking !!
, and why didn’t it give us back our original value?
Type Coercion – Good Friend or Deadly Foe?
If you’ve read some of our other tutorials, you’ll have seen other examples of type coercion, and the issues (and benefits) of such a system.
As a quick refresher, type coercion is the process of converting a value of one type, into another. There are certain rules which the coercion process follows, such as converting an integer 0 or empty string to false when comparing with a boolean.
So let’s go back to our example. If we substitute our value, we have
!!10
You might think this would return 10 – we’re negating it, then negating it again. In reality, this comes from a common misunderstanding of the !
operator. It’s not a simple negation operator, despite often being described as one (including in the opening of this article).
Rather, it’s a comparison to the boolean false
.
In practice, this does seem to work like a negation operator in many instances, including when used as part of the common !=
or !==
clauses (not equal, rather than equal).
But thinking of it as a negation operator can sometimes lead to unintended side effects, and makes the !!
appear more complicated than it really is.
Let’s expand our previous code, to include the two separate comparisons taking place
false == (false == 10)
In terms of function, this is exactly the same as our other code, but shows more clearly why the result is not the value 10.
When comparing false
to 10, the value 10 is converted to a boolean due to type coercion. A non-zero integer value is equivalent to true in boolean, leaving us with
false == (false === true)
I’ve replaced the ==
with ===
inside our parentheses, as the type on each side now matches.
The code inside the parentheses evaluates to false, leaving us with
false === false
The result is a boolean, so no type coercion is not needed this time. We can see that the final result of this equates to true, which is what we saw when running our code at the start of the article.
So in practice, the !
operator does act as a negator – but only after the value has been converted to a boolean. It’s important to understand this, and consider how type coercion can impact the result of your comparisons.
So Why Would We Use !!?
That’s a great question. And personally, I don’t think there’s a great use case for it. But let’s consider what we can do with it.
In our example, we began with the number 10. Converted to a boolean, this becomes true
– the same result as !!
10.
Where you find !!
, the goal is to convert the value to a boolean. There’s no shorthand way of doing this. The best we can do, is to negate the value as well, using !
. This gives us a boolean, but with the opposite value to the original. So to get back to our original result, we have to negate it again. (And yes, I’ve referred to it as negation again – just don’t forget the type coercion involved).
There are circumstances where an explicit boolean value is beneficial – and is even required in some cases when using JS frameworks, such as React.
Now, it’s important to say that this isn’t incorrect – it does the job it’s intended to do. There are other ways to achieve this though, such as explicit type conversion.
Boolean(10)
Note that this is considered type conversion, or type casting, as we’re the ones doing the converting. It’s only considered type coercion when the conversion is handled by the JS interpreter – an implicit conversion.
Be careful when applying this terminology to other programming languages, as conversion, casting and coercion don’t always have the same meaning.
In my opinion, explicit type conversion would be the way to go – it’s much less ambiguous. You can see straight away that this is converting our value to a boolean. You do still need to be aware of type coercion rules though – take a look at our article on avoiding coercion pitfalls to brush up on the basics.