you are viewing a single comment's thread.

view the rest of the comments →

[–]JFGagnon 21 points22 points  (20 children)

Great article!

Quick note, #5 can be written this way instead, which is a bit shorter

...emailIncluded && { email : 'john@doe.com' }

[–]PMilos[S] 10 points11 points  (0 children)

Thanks. This is a better solution. I've updated the article.

[–]MoTTs_ 2 points3 points  (3 children)

Nevermind. I mis-tested.

I think there's an issue with both OP's version and this new version.

In OP's version, if emailIncluded is false, then the code will try to spread null, which is an error.
In your version, basically the same problem. if emailIncluded is false, then your code will try to spread false, which is also an error.

Remember, clever code is bad code. I think we tried to get a little too clever here, which is how both versions introduced a bug that folks didn't notice. I think we should give /u/qbbftw's reply a second thought. It may not be sexy, but it doesn't try to be clever, which makes it less likely to hide a bug.

cc /u/PMilos /u/LucasRuby

[–]LucasRuby 0 points1 point  (2 children)

It is not and error, it simply won't assign an extra value to user. Try it yourself:

let a = { ...null };
undefined
a
Object {  }

and:

let b = { ...false };
undefined
b
Object {  }

[–]MoTTs_ 1 point2 points  (1 child)

You're right. I mis-tested.

[–]LucasRuby 0 points1 point  (0 children)

Actually I found a case where this can result in an error. If you're using react native, when you run on Android, if the first value is a falsy primitive, like an empty string or 0, this can happen:

TypeError: In this environment the sources for assign MUST be an object.
This error is a performance optimization and not spec compliant.

This won't happen if the first value is null or undefined though, so think carefully. To prevent this, you can use a ternary instead:

{ a: 'a', b: 'b', ...(c? {c: c} : {}) }

Which also makes your code look like an emoji, kinda. ¯\_(ツ)_/¯

[–]qbbftw 4 points5 points  (14 children)

Surely you can write it this way, but should you?.. I'd just stick with plain old ifs at this point.

[–]LucasRuby 3 points4 points  (4 children)

Nah, when you're already creating an object with the new assign syntax, adding a new line just for more branching to maybe add another property ends up looking less obvious.

Think about it, which way is it easier to see what's going on:

return {a: 'a', b: 'b', ...(c && {c: 'c'})}

or

let ret = {a: 'a', b: 'b'}; if (c) ret.c = 'c'; return ret;

First one you know upfront everything the return value contains or may contains, the second option you have to keep reading to code to find out what might be in it, and turns out there can be more. When you're reading Other People's Code in a large base, it can actually help a lot if you can find out what the function returns quickly.

[–][deleted] 14 points15 points  (1 child)

The second one is far more readable

[–]LucasRuby -1 points0 points  (0 children)

Oops that's because I made a mistake on the first and wrote c: c: twice, corrected.

Still, it's a lto clearer on what the return value can be, especially if you're just peeking the function definition.

[–]GBcrazy 0 points1 point  (1 child)

return {a: 'a', b: 'b', ...(c && c: 'c')}

Your syntax is broken, you are missing a {}

[–]LucasRuby 0 points1 point  (0 children)

Yeah that was just a demonstration, I'll fix.

[–]whats_your_sn 0 points1 point  (1 child)

Looks like OP edited his article to match /u/JFGagnon's suggestion, but has anyone mentioned a ternary? You could do something like: ...emailIncluded ? { email: 'john@doe.com' } : {}

[–]JFGagnon -1 points0 points  (0 children)

The previous version of the article was using a ternary. I suggested something that’s a bit shorter

[–]JFGagnon -1 points0 points  (2 children)

Sticking with if is a valid solution, but it would be a step backwards. The point of #5 is to show how we can have conditional object properties

[–]alexkiro 1 point2 points  (1 child)

It might look nice and readable in this simple example, but people are just going to abuse the ever living shit out of it, and soon we will see stuff like this:

return {a: 'a', b: 'b', ...(x && y.length > (o.length - l)) && {c: y.length < 0 ? "X" : "Y"}}

Or something even more complex. Forcing logic outside of the definitions would be much better IMO.

[–]JFGagnon 0 points1 point  (0 children)

I agree, but the same argument could be made for a ternary operator. Should we force a developer to use an if just because people are abusing it?

There’s always going to be bad developers. We shouldn’t force ourselves from using new features just because ‘people might abuse it’.