22

I find myself presented with this pattern quite a bit. I have an array of objects that I get back from my api, and I need to manipulate just one of the properties in all of the objects.

Is there a way using ES6/Babel or Typescript to get that pattern to be a little more declarative?

Looking for some neat destructuring trick or something along those lines.

const data = [{ foo: 1, bar: 2}, 
              { foo: 2, bar: 3},
              { foo: 3, bar: 4}];

const increment = a => a + 1;

// Here is my typical pattern
const result = data.map(o => {
    o.foo = increment(o.foo);
    return o;
})

console.log(result);

4
  • do you need a new object? Commented Feb 17, 2017 at 20:12
  • What is the point of the new array if you're modifying the objects inside the old one in place anyway? Commented Feb 17, 2017 at 20:22
  • @pvg Yeah, I could edit my question. The point is that there may be some operation that I need to perform on a property. Whether or not the array needs to be a new array or just mutated was kind of secondary, I really just wanted to see if there was a more declarative way to write what I seem to do a lot, in my current project. Commented Feb 17, 2017 at 20:34
  • I guess I'm not entirely understanding the 'declarative' criterion. That is, what, beyond direct use of map and forEach makes this more... something? Is there a construct in another language you have in mind? Commented Feb 17, 2017 at 20:39

5 Answers 5

40

Object spread (...), available in Babel using the Stage 3 preset, does the trick:

const data = [
  { foo: 1, bar: 2 }, 
  { foo: 2, bar: 3 },
  { foo: 3, bar: 4 },
];

const increment = a => a + 1;

const result = data.map(o => ({ ...o, foo: increment(o.foo) }));
console.log(result);

Sign up to request clarification or add additional context in comments.

5 Comments

that's not part of the specs (still).
@Hitmands OP specifically asked for solutions that work with Babel.
he said: Is there a way using ES6/Babel or Typescript to get that pattern to be a little more declarative?.
@Hitmands Yep. And that's exactly what my answer demonstrates.
I love Object.assign, but this is a great case for the spread operator.
9

This is a little more elegant I think - Object.assign is a good way to update an item in an object

const data = [{
  foo: 1,
  bar: 2
}, {
  foo: 2,
  bar: 3
}, {
  foo: 3,
  bar: 4
}];

const increment = a => a + 1;

// Here is my typical pattern
const result = data.map(o => Object.assign(o, {foo: increment(o.foo)}))

console.log(result);

2 Comments

Just amazing!,,
Super. Worked like a charm.
4

For a in situ version, you could use a closure over the key of the object and take the object as parameter.

const data = [{ foo: 1, bar: 2 }, { foo: 2, bar: 3 }, { foo: 3, bar: 4 }];
const increment = k => o => o[k]++;

data.forEach(increment('foo'));
console.log(data);

1 Comment

I really love this technique! I'm a little worried other devs might question what's happening, but I guess it'd be a good learning session!
1

what about:

data.map(d => (
  Object.assign({}, d, {foo: d.foo + 1})
));

Comments

1

Isn't all this completely equivalent to just:

const data = [{ foo: 1, bar: 2 }, { foo: 2, bar: 3 }, { foo: 3, bar: 4 }];

const result = data.slice();
result.forEach(e => e.foo++);
console.log(result);

5 Comments

Yep, in this exact scenario, you rewrote the code exactly, but in reality I'm not incrementing properties by 1. There could be operations for dates, strings, prototypical objects with methods on them. So while your answer is correct, it doesn't actually answer my problem.
@Richard.Davenport Ok so this about the transformations themselves? ES6 destructurinng, computer property names and all that can probably help there but it's hard to talk about concretely without some idea of the transformations you are doing. forEach and map are already 'declarative' (in fact, in your example since you're mutating rather than mapping, you could argue that forEach is more 'declarative'.
I think we're talking past each other, mind you, we both have opinions and that's what most of this is. You bring up excellent points, but your code, while concise, doesn't read well. Again, opinion. Have you ever read a grammatically terrible tweet? Or a pretentious tweet with latin in it? It's like, we're both speaking english, but having a hard time with the semantics.
Right, but I'm trying to understand the transformations you have in mind in which the in which greater reliance on composition and potentially newer syntactic features come into play. There are such things, entire APIs and libraries of them, but they tend to be constrained to specific classes of transformation. I don't think there is a general answer for the general case. (Agreed about opinions, though, for this particular transformation, my code is a vast improvement over yours :)
Hahahaha, whatever you say pvg! I think we'd work well together.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.