An Example of JavaScript Double Negative

javascript double negative
Image credit:

I remember the first time I saw JavaScript double negative syntax. It confused the heck out of me – so much so, I thought it was a mistake.

Over time, I have seen other developers equally confused. It must get asked in Slack at least once a quarter, if not more.

In case you aren’t sure, let’s quickly cover exactly what we are talking about here:

{ isAuthenticated: !!localStorage.getItem('idToken') }

The point of interest here being the double negative / double bang / !! / double exclamation marks. I put all the alternatives I can think of in, in the hope that it helps others searching for similar.

It’s also worth pointing out that double exclamation marks are not a single operator. I guess that makes it all the more difficult to Google, and understand.

Just Tell Me What It Is

For the impatient, using Javascript double negative / not not will coerce your value to a boolean, and ensure that the output is of type boolean.

To translate that from technobabble:

The first ! will convert a value that isn’t either true or false into a value that is  true or false, and then invert it.

The second ! will invert it again.


An example illustrates a potential use case, which hopefully will make it slightly easier to understand.

Just Show Me An Example

Here is a real world example from an authentication reducer I am currently working on in a React / Redux project.

Let’s look at the code as it stands before adding in the double negatives:

import {
} from '../constants/ActionTypes';

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken')
}, action) {

  switch (action.type) {

    case LOGIN__SUCCESS:
      return Object.assign({}, state, {
        isAuthenticated: true,
        userId: action.userId,

    case LOGIN__FAILED:
      return Object.assign({}, state, {
        isAuthenticated: false,
        errorMessage: action.errorMsg

      return Object.assign({}, state, {
        isAuthenticated: false

      return state;

Most of this is not that interesting in the context of this particular example.

I have highlighted line 9 where localStorage is used to retrieve the user’s idToken, should it exist.

There is a bug in this code.

The default case of the switch statement means that when a user first loads the page / before they have ever logged in, the default state would return:

  sendingRequest: false,
  isAuthenticated: null

Instead, I want it to be:

  sendingRequest: false,
  isAuthenticated: false

I could use a ternary operator to fix this:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken') ? true : false
}, action) {

And this would work, but WebStorm moans at me that I can do better:

WebStorm telling me I suck

I make the change:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: !!localStorage.getItem('idToken')
}, action) {

Why does this work?

Because by localStorage.getItem(‘idToken’) is going to either return me a string (containing my locally saved idToken), or as we have already seen, a null.

If we check whether a string is not (!) something, we would get false – because a string is definitely something.

It therefore stands that if a string is not not something, then it must be true.

Likewise, if we check if a null is not (!) something, we would get true – because a null is definitely nothing.

It equally therefore must stand that if a null  is not not nothing, then it must be false.

Still confused? Don’t feel down about it. It took me ages to grasp this, and it’s so unusual that it really won’t come up that frequently.

I would even go as far as to say consider sticking with the ternary operator approach. It is simply easier for most developers to immediately understand, even if WebStorm moans about it.

Published by

Code Review

CodeReviewVideos is a video training site helping software developers learn Symfony faster and easier.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.