Search code examples
javascriptfunctional-programminglodash

Using lodash's fp functions in a flow


Having read that the _.chain method is "considered harmful" I thought I should attempt some flow instead. However, I'm running into an issue using the fp methods.

I've added a small example to a repl and reproduced the code below as well.

const flow = require('lodash/fp/flow');
const truncate = require('lodash/fp/truncate');
const mapValues = require('lodash/fp/mapValues');
const { inspect, format } = require('util');

const input = {
    firstField: 'I am a fairly long string so I want to be truncated',
    secondField: {
        foo: 'bar',
        bar: 'baz',
        baz: 'boo',
        boo: 'hoo',
        hoo: 'boy',
        boy: 'howdy'
    }
};

const doTheThing = data =>
    flow(
        mapValues(inspect), 
        mapValues(s => s.replace(/\s*\n\s*/g, ' ')),
        mapValues(truncate)
    )(data);

console.log(doTheThing(input));

When I run this, truncate isn't invoked how I expect it to be, and for output I get

{ firstField: { [Function: wrapper] placeholder: {} },
  secondField: { [Function: wrapper] placeholder: {} } }

I'm expecting to get back two truncated strings, not functions that have been toString'd. To get that, I have to change it to mapValues(s => truncate(s)(s)). This looks wrong to say the least, so have I wrongly combined flow and fp methods, or am I using them wrong?


Solution

  • You are using them wrong. First of all with ordinary Lodash the truncate function takes two parameters:

    _.truncate([string=''], [options={}])

    where the second one is:

    [options={}] (Object): The options object.

    With Lodash fp there are no optional arguments and some functions' arguments are rearranged to make composition easier. So in fp truncate takes two parameters, first of which is the options object. To truncate a string with fp you need to provide two parameters:

    const truncFn = _.truncate({ length: 20 }); // is a function
    const truncatedString = truncFn('I am a fairly long string so I want to be truncated'); // only this results in truncated string
    
    console.log(truncatedString);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.fp.min.js"></script>

    Your snippet, fixed version (repl link):

    const flow = require('lodash/fp/flow');
    const truncate = require('lodash/fp/truncate');
    const mapValues = require('lodash/fp/mapValues');
    const { inspect, format } = require('util');
    
    const input = {
        firstField: 'I am a fairly long string so I want to be truncated',
        secondField: {
            foo: 'bar',
            bar: 'baz',
            baz: 'boo',
            boo: 'hoo',
            hoo: 'boy',
            boy: 'howdy'
        }
    };
    
    const doTheThing = data =>
        flow(
            mapValues(inspect), 
            mapValues(s => s.replace(/\s*\n\s*/g, ' ')),
            mapValues(truncate({})) // <--- FIX
        )(data);
    
    console.log(doTheThing(input));