1

Often I have several named variable, and I want to put them into an object if they are not null or undefined. JavaScript has several nice shortcuts for building objects, so I figure there must be one for this use case.

I usually do something like this. But it is so verbose.

function foo(a, b) {
  return {...(isNotNullish(a) ? {a} : {}), ...(isNotNullish(b) ? {b} : {})};
}
// the result I want is:
// foo(6, 7) == {a: 6, b: 7}
// foo(6) == {a: 6}
// foo() == {}

Is there a better way?

Samuel Hulla
  • 6,617
  • 7
  • 36
  • 70
cowlicks
  • 1,037
  • 1
  • 12
  • 20
  • 2
    You can use `...(a || {})` –  Nov 10 '20 at 18:28
  • @ChrisG or `...(a ?? {})` nowadays – VLAZ Nov 10 '20 at 18:32
  • Possible duplicate: [Is there a "null coalescing" operator in JavaScript?](https://stackoverflow.com/questions/476436/is-there-a-null-coalescing-operator-in-javascript) –  Nov 10 '20 at 18:36
  • @VLAZ that doesn't work, you'd have to wrap a in an object – cowlicks Nov 10 '20 at 19:44
  • @ChrisG I would need a *not* nullish operator for this to work inline. Note `...(a || {})` doesn't work. Try it. You'd need to wrap `a` in an object only if it is *not* nullish. – cowlicks Nov 10 '20 at 19:48
  • I see, shortest way I can find: `{...(a ? {a} : 0), ...(b ? {b} : 0)}` –  Nov 10 '20 at 20:08

3 Answers3

2

I'm afraid there's no real shorter way of doing this (well technically a minor one and then somewhat more obtuse one)

I tried playing around with the nullish operator ??, but I have to say the working solution seems uglier than what I'm a bout to propose.

Essentially it boils down to the fact, you're looking for the negation of the nullish operator (or alternatively a nullish ternary), neither of which sadly exist (yet).

Here's a relatively compact solution, which just improves upon your solution and simplifies it with the usage of the && logical AND operator

const notNullish = (value) =>
  value !== null && typeof value !== 'undefined'

const foo = (a, b) => ({
  ...(notNullish(a) && {a}),
  ...(notNullish(b) && {b}),
 })

console.log('foo(6, 7) =>', foo(6, 2))
console.log('foo(6) =>', foo(6))
console.log('foo() =>', foo())
console.log('foo(0, false) =>', foo(0, false))

Now as I said, there's no optimal way of doing this, because while the you can use the logical ?? to check, it cannot directly assign to object property at the same time. Best I could come up with is:

const notNullish = (key, value) => {
   const nullishCheck = value ?? 'IS_NULLISH'
   return nullishCheck === 'IS_NULLISH'
      ? {}
      : {[key]: value}
}

const foo = (a, b) => ({
   ...notNullish('a', a),
   ...notNullish('b', b)
})

console.log(foo(6, 4))
console.log(foo(6))
console.log(foo())
console.log(foo(0, false))

But personally I find the second snippet kinda ugly and would probably just go with the first option, especially for the following three reasons

  1. In my opinion it just looks plain uglier
  2. The ?? operator is not yet fully supported on Explorer and Node.js
  3. Chances are not a lot of people are even familiar with the operator and it forces you to not even use it directly, but rather as an assignment check.
Samuel Hulla
  • 6,617
  • 7
  • 36
  • 70
1

What about

return Object.assign({}, a, b);

It will simply ignore nullish values or spread if objects

quirimmo
  • 9,800
  • 3
  • 30
  • 45
  • That doesn't work the way you say it does. ```> function foo(a, b) { ... return Object.assign({}, a, b); ... } undefined > foo(6) {} > foo(6, 7) {} > foo() {}``` – cowlicks Nov 10 '20 at 19:52
  • Yes but I thought others could be null undefined pr otherwise objects that Marge them – quirimmo Nov 11 '20 at 09:56
1

I know this is an old question but for future reference, I was looking for a way to do this in the case a role wasn't provided when creating my User. I think this should work fine for a scenario similar to this:

const user = await User.create({
  email, password, ...(role && { role })
});
Alexiz Hernandez
  • 609
  • 2
  • 9
  • 31
  • I actually do use a pattern like this quite often but it is for a special case where the variable (`role` here) must be **truthy** – cowlicks Feb 17 '23 at 18:25