tc39/proposal-object-rest-spread

Is the behavior of {...false} defined? (Conditionally setting key)

qria opened this issue ยท 4 comments

qria commented

This stackoverflow answer recommends using spread operator to conditionally set a key in a object.

const animal = {species: 'cat'};
const vocalAnimal = {
    ...animal,
    ...animal.species === 'cat' && {purr: 'meow'},
    ...animal.species === 'dog' && {bark: 'woof'},
} 
// becomes: { "species": "cat", "purr": "meow" }

But this depends on a behavior of ...false being ignored, like ...null or ...undefined.
Similar code without depending on the behavior might be:

const animal = {species: 'cat'};
let vocalAnimal = {...animal};
if(animal.species === 'cat'){
    vocalAnimal.purr = 'meow';
}
if(animal.species === 'dog'){
    vocalAnimal.bark = 'woof';
}

So is the behavior well defined/ intended/ dependable?

Yes, it should mirror Object.assign.

In other words, your first example must be equivalent to const vocalAnimal = Object.assign({}, animal, animal.species === 'cat' && {purr: 'meow'}, animal.species === 'dog' && {bark: 'woof'}); - and Object.assign will treat all primitives (like undefined) as the same as {} - in other words, this works just fine as-is.

Yes, it should mirror Object.assign.

I know it's too late, but IMO the error throwing would be much more helpful. There's no way to opt into error throwing in {...obj.undefinedVariable} if one didn't expect it to be undefined, however it is easy to opt out of error throwing with {...(obj.undefinedVariable || {})}. Error throwing instead of silence would point to possible errors like typos, code load order issues, wrong variables, etc.

Why should it mirror Object.assign? I mean, how is mirroring that more beneficial?

Well, I see that

const a = {
   ...(someCondition && {b: 5})
}

is convenient, but IMO not more convenient than preventing bugs ๐Ÿ›๐Ÿž.

If object spread threw like ...iterable does, then I'd be explicitly opting into non-errors by writing

const a = {
   ...(someCondition && {b: 5} || {})
}

which would be nice.

const a = {
   ...(someCondition && {b: 5} || {})
}

@trusktr How about the code below? I think this will also handle errors

const a = {
... someCondition ? {b: 5} : {}
}