Open utterances-bot opened 2 years ago
FWIW it seems like its not only booleans that work
f = { ...null && { a:1 } }
{}
{ ...true && { a:1 } }
{a: 1}
{ ..."" && { a:1 } }
{}
Also, a matter of style, but maybe good to wrap the boolean expressions in parens to reduce opportunity for confusion.
const activeUsers = {
...(isActive && user)
};
FWIW it seems like its not only booleans that work
f = { ...null && { a:1 } } {} { ...true && { a:1 } } {a: 1} { ..."" && { a:1 } } {}
Also, a matter of style, but maybe good to wrap the boolean expressions in parens to reduce opportunity for confusion.
const activeUsers = { ...(isActive && user) };
Have you tried a non empty string or any non primitive value?
A non empty string does act as a truthy value, and the object gets spread.
As for non-primitives, even if an object's valueOf
returns false, the object itself being a non-null reference takes precedence and is truthy.
const obj = {
a: 23,
b: '42',
};
const spread1 = {
...('Will it blend ?' && obj),
};
console.log('spread1: ' + JSON.stringify(spread1));
// --- //
const nonPrimitive = {
valueOf: () => false,
};
console.log(
'Non primitive truthiness check :\n',
'\t- nonPrimitive == false -> ' + (nonPrimitive == false) + '\n',
'\t- nonPrimitive === false -> ' + (nonPrimitive === false) + '\n',
'\t- nonPrimitive && true -> ' + (nonPrimitive && true)
);
const spread2 = {
...(nonPrimitive && obj),
};
console.log('spread2: ' + JSON.stringify(spread2));
Basically it works like any other test when it comes to determining truthiness, and as this MDN page mentions
In JavaScript, a truthy value is a value that is considered true when encountered in a Boolean context. All values are truthy unless they are defined as falsy. That is, all values are truthy except
false
,0
,-0
,0n
,""
,null
,undefined
, andNaN
.
As a matter of fact, even empty objects {}
and empty arrays []
are non null references and evaluate to true.
Very nice tip. Just for fun purposes you can use async await inside these "spreadable expressions" as well:
const asyncValid = Promise.resolve(true)
const asyncInvalid = Promise.resolve(false)
async function asyncOperation() {
const valid = {
foo: 'valid'
}
const invalid = {
bar: 'invalid'
}
const someObject = {
...(await asyncValid && valid),
...(await asyncInvalid && invalid)
}
console.log({ someObject })
}
asyncOperation()
I would not do that, but it's always awesome to discover straight ways to do something...
This is so cool!
The catch here is that in the {...val}
expression
val
as an object and makes the necessary coersion if it's not an object. String values are evaluated as String objects, false/true as Boolean objects. Null is an object on its own...
enumerates the own properties of the object. String, Boolean, null objects do not have own properties, hence their destructuring is equivalent to destructuring of an empty object {...{}}
Conditionally spreading objects in JavaScript — Amit Merchant — A blog on PHP, JavaScript, and more
In JavaScript, if you want to populate an object with some properties from another object, you can use the spread operator (...) to do so.
https://www.amitmerchant.com/conditionally-spreading-objects-in-javascript/