-1

Is there a better way to accomplish this in Javascript?

const data: any = {};
if (values.email) data.email = values.email;
if (values.password) data.password = values.password;
if (values.username) data.username = values.username;

I don't want the data object to have the properties for the undefined or falsy values.

Diesel
  • 5,099
  • 7
  • 43
  • 81

4 Answers4

0

You could put the potential properties in an array and then .filter() out any which values[prop] has a fasly value for. Then you can .map() each key to an array of [key, value] pairs, and use Object.fromEntries() to build the data object for you:

const values = {
  email: 'abc',
  username: 'xyz'
};

const props = ['email', 'password', 'username'];
const data = Object.fromEntries(
  props.filter(prop => values[prop]).map(prop => [prop, values[prop]])
);

console.log(data);

If you can't support Object.fromEntries(), you could consider using Object.assign(), and then mapping to an array of objects which you then spread into Object.assign():

const values = {
  email: 'abc',
  username: 'xyz'
};

const props = ['email', 'password', 'username'];
const data = Object.assign({},
  ...props.filter(prop => values[prop]).map(prop => ({[prop]: values[prop]}))
);

console.log(data);
Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
  • I would expect that too many of the environments which don't support `Object.fromEntries` would also not support spreading in an object initializer. In that case, I would choose a fallback using `reduce` as in the answer from *theDude*. – Scott Sauyet Apr 13 '20 at 15:06
  • 1
    @ScottSauyet the second snippet should be es6 compatible, as it is using the spread syntax to spread the _arguments_ into the assign method (rather than the es2018 feature of spreading into an object literal). – Nick Parsons Apr 13 '20 at 15:19
  • 1
    Yes, I misread. That should be supported in all ES6 environments. – Scott Sauyet Apr 13 '20 at 15:47
  • Thanks, I was hoping that there would be a javascript function or this in ES6. Guess not. – Diesel Apr 13 '20 at 16:49
0

You can do something along these lines:

const obj1 = {
  prop1: true,
  prop2: false,
  prop3: 4,
}

const obj2 =  Object.entries(obj1).reduce((result, [key, value]) => {
  if (value) {
    result[key] = value
  }
  return result
}, {})

console.log(obj2)
thedude
  • 9,388
  • 1
  • 29
  • 30
0

This simple function will do it, if you want to copy over all properties that don't have a false-y value. If you only want a fixed list, look at the answer from Nick Parsons.

const copyNonNil = (obj) => 
  Object .fromEntries (Object .entries (obj) .filter(([k, v]) => v))

const values = {
  email: 'foo@bar.baz',
  username: 'foobar',
  password: '',
  another: false
}

console .log (copyNonNil (values))

It's easy to shim Object .fromEntries if you don't have it available. See the answer from theDude, which uses a reduce that serves in the same role.

Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
0

You could use Object.entries to iterate over the properties of values and perform the true/false check in that to make this more flexible:

for(const [key, value] of Object.entries(values)){
    if(values[key]) data[key] = value;
}

This would give you only the truthy values in data for a values object of any size.