Nick Cox Nick Cox - 4 months ago 32
Javascript Question

What's the lodash/fp equivalent of Ramda's 'evolve' function?

Looking for a lodash equivalent of Ramda's evolve:

const transformForDisplay = (item) => {
const transform = {
body: truncate({ length: 100 }),
title: truncate({ length: 50 })
}

return R.evolve(transform, item)
}


Which returns an object containing all of the original fields from 'item' but truncating the 'body' and 'title' fields if they exist.

Edit: this works. Anything more pithy?

const transformForDisplay = (item) => {
const transform = {
body: truncate,
title: truncate
}

const mapValuesWithKey = _.mapValues.convert({ cap: false })
return mapValuesWithKey((x, key) => transform[key] ? transform[key](x) : x)(item)
}

Answer

I wasn't able to find any built-in equivalent. Here's how you might implement evolve yourself.

It's pretty much what you already had, except I used _.getOr to avoid having to repeat transform[key], and I added a recursive call to evolve when necessary.

// Implementation    

const mapValuesWithKey = _.mapValues.convert({cap: false});

function evolve(transform) {
  return item =>
    mapValuesWithKey((x, key) => {
      const t = _.getOr(_.identity)(key)(transform);
      const type = typeof t;
      return type === 'function' ?
        t(x) :
        t && type === 'object' ?
          evolve(t)(x) :
          x;
    })(item);
}

// Example    

const tomato  = {
  firstName: '  Tomato ',
  data: {elapsed: 100, remaining: 1400},
  id: 123
};
const transformations = {
  firstName: _.trim,
  lastName: _.trim, // Will not get invoked.
  data: {elapsed: _.add(1), remaining: _.add(-1)},
  id: null, // Will have no effect.
}
const result = evolve(transformations)(tomato);
console.log(result);
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.fp.min.js"></script>