Search code examples
javascriptlodashramda.js

Is there a 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)
}

Solution

  • 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(transformations) {
      return item =>
        mapValuesWithKey((value, key) => {
          const transformation = _.getOr(_.identity)(key)(transformations);
          const type = typeof transformation;
          return type === 'function' ?
            transformation(value) :
            transformation && type === 'object' ?
              evolve(transformation)(value) :
              value;
        })(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>