6

I was reading through this: https://github.com/pburtchaell/redux-promise-middleware/blob/master/src/index.js

I know that ... is being used as Object spread. I know that !! is used to convert anything into a boolean with the same truthiness.

However knowing this what do they mean when they're put together like ...!!? I have trouble understanding the last line here:

{
  ...resolveAction,
  ...isAction(rejected) ? rejected : {
    ...!!rejected && { payload: rejected }
}
  1. ...resolveAction just spreads the keys of resolveAction.
  2. ...isAction(rejected) ? will check if rejected resolves an action and then will spread it. (Not sure about this one either)
  3. add rejected to object if true
  4. {...!!rejected && { payload: rejected } ????????????????

How is ...!! even valid syntax? There are two options:

  1. If it spreads the object first, then !! would be applied to all the spread keys

  2. If !! is applied first it's a boolean value and it can't be spread.

So does it make no sense whatsoever, or am I missing something because given that code, I assume it's trying to spread a boolean value.

m0meni
  • 16,006
  • 16
  • 82
  • 141
  • In that repo, `rejected` is an object (line 54). Maybe the spread operator in conjunction with `!!` inverts each property of the object? – Scott Jan 24 '16 at 04:43
  • 1
    My guess is, and this is only a guess since I haven't found anything in the ES6 spec about precendences, that `...` has a low precedence so actually the spread is applied to `rejected && { payload: rejected }`. So what the code is actually testing is that there is a rejected value and if so pass it as a key called `payload` – nbermudezs Jan 24 '16 at 04:44
  • @nbermudezs I think you're on to something. An `&&` will return the second value if the first is truthy, so the object gets spread into the parent object. – L3viathan Jan 24 '16 at 04:47
  • 3
    @nbermudezs If that's the case, I'd argue the maintainers of redux should add some brackets to make this more clear, and not end up with [questions like this](http://stackoverflow.com/questions/1642028/what-is-the-name-of-the-operator). – Scott Jan 24 '16 at 04:47
  • @ScottKaye lol, yeah, although it is arguable that the maintainers will like to stick with a code style exploiting the most out of the language therefore knowing deeply the language is a must – nbermudezs Jan 24 '16 at 04:50
  • @ScottKaye this isn't made by the creator, but rather is made by community member. However, I agree that it's pretty bad, and I've since written my own version. – m0meni Jan 24 '16 at 05:46
  • Using `!!` to force a value to be treated as a boolean is an idiomatic thing in JavaScript. I'm not sure I see the problem here. – Pointy Jan 24 '16 at 14:52
  • Ok right, that makes sense :) – Pointy Jan 24 '16 at 17:19
  • That seems to be missing a closing brace, doesn't it? – Bergi Aug 18 '16 at 21:08

2 Answers2

3

Okay so after downloading the npm module and going through the transpiled code I found the line:

return dispatch(isThunk(rejected) ? rejected.bind(null, resolveAction) : _extends({}, resolveAction, isAction(rejected) ? rejected : _extends({}, !!rejected && { payload: rejected })));

Of which the relevant part is here:

_extends({}, !!rejected && { payload: rejected })

Basically if !!rejected is true then it'll spread the payload into the object. If it's not _extends({}, false) just returns {}.

The key to this working is that ... has less precedence than any other operator in the entire line. With that in mind you can begin to make sense of it.

m0meni
  • 16,006
  • 16
  • 82
  • 141
1

The relevant question is What is "x && foo()"?

The weird syntax

{...!!rejected && { payload: rejected }}

is parsed as

{ ... ((!!rejected) && { payload: rejected }) }

Indeed the !! does cast rejected to a boolean, then it is evaluated to the object when truthy. A better way to write this would be

{ ...(rejected ? {payload: rejected} : null) }

And of course the whole inner object literal is superfluous. It could just be

{
  ...resolveAction,
  ...(isAction(rejected) ? rejected : (rejected ? {payload: rejected} : null))
}

(omit parentheses as you see fit)

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • At the time that I asked this, I genuinely thought ...!! was some kind of unique operator. I knew what && meant, but didn't know how low the precedence of ... was which was the key to figuring it out. So while this answer is right, it misses the mark on what I was actually asking which would be "in what order is (...) (!!) and (&&) evaluated" – m0meni Aug 18 '16 at 21:28
  • @AR7: I think the "is parsed as" paragraph explains precedence/evaluation order, doesn't it? – Bergi Aug 18 '16 at 21:30
  • yeah I agreed with you there and said "the answer is right." The only part I have issue with is he first sentence. I know what 'x && foo()' means. The caveat here is that it was '...!!x && foo()', which confused me. – m0meni Aug 18 '16 at 21:34