compose

compose

  • (fnArray: function[]) => (...args: any[]) => Result
  1. Create a function that passes a value through fnArray.

    Each function takes the result of the prior function as its parameter.

    const increment = n => n + 1
    const double = n => n * 2
    const toAnswer = n => 'answer: ' + n
    
    const calculate = compose([increment, double, toAnswer])
    
    calculate(1) // is 'answer: 4'
    
    const returnFirstArg = compose([])
    returnFirstArg('a', 'b') // is 'a'
    const increment = (n: number) => n + 1
    const double = (n: number) => n * 2
    const toAnswer = (n: number) => 'answer: ' + n
    
    const calculate = compose([increment, double, toAnswer])
    
    calculate(1) // is 'answer: 4'
    
    const returnFirstArg = compose([])
    returnFirstArg('a', 'b') // is 'a'
    
    const increment = n => n + 1
    const double = n => n * 2
    const toAnswer = n => 'answer: ' + n
    
    const calculate = compose([
      increment,
      double,
      toAnswer,
    ])
    
    calculate(1) // is 'answer: 4'
    
    const returnFirstArg = compose([])
    returnFirstArg('a', 'b') // is 'a'
    const increment = (n: number) => n + 1
    const double = (n: number) => n * 2
    const toAnswer = (n: number) => 'answer: ' + n
    
    const calculate = compose([
      increment,
      double,
      toAnswer,
    ])
    
    calculate(1) // is 'answer: 4'
    
    const returnFirstArg = compose([])
    returnFirstArg('a', 'b') // is 'a'
    
  2. Just like passThrough, compose gives us a flexible and readable way to combine logic. It's one of the big reasons I find functional programming to be helpful.

    Below, we have the five-day weather forecast. Let's compose a function to get the average low.

    const forecast = [
      { high: 68, low: 54 },
      { high: 62, low: 50 },
      { high: 63, low: 52 },
      { high: 55, low: 43 },
      { high: 58, low: 49 },
    ]
    
    const getAvgLow = compose([
      mapValues(get('low')),
      getAverageValue,
      roundToNearest('0.1'),
    ])
    
    const avgLow = getAvgLow(forecast)
    console.log(avgLow)
    // is 49.6
    type Forecast = {
      high: number
      low: number
    }
    
    const fiveDayForecast: Forecast[] = [
      { high: 68, low: 54 },
      { high: 62, low: 50 },
      { high: 63, low: 52 },
      { high: 55, low: 43 },
      { high: 58, low: 49 },
    ]
    
    const getAvgLow = compose([
      mapValues(get('low'))<Forecast[]>,
      getAverageValue,
      roundToNearest('0.1'),
    ])
    
    const avgLow = getAvgLow(fiveDayForecast)
    console.log(avgLow)
    // is 49.6
    
    const forecast = [
      { high: 68, low: 54 },
      { high: 62, low: 50 },
      { high: 63, low: 52 },
      { high: 55, low: 43 },
      { high: 58, low: 49 },
    ]
    
    const getAvgLow = compose([
      mapValues(get('low')),
      getAverageValue,
      roundToNearest('0.1'),
    ])
    
    const avgLow = getAvgLow(forecast)
    console.log(avgLow)
    // is 49.6
    type Forecast = {
      high: number
      low: number
    }
    
    const fiveDayForecast: Forecast[] = [
      { high: 68, low: 54 },
      { high: 62, low: 50 },
      { high: 63, low: 52 },
      { high: 55, low: 43 },
      { high: 58, low: 49 },
    ]
    
    const getAvgLow = compose([
      mapValues(get('low'))<Forecast[]>,
      getAverageValue,
      roundToNearest('0.1'),
    ])
    
    const avgLow = getAvgLow(fiveDayForecast)
    console.log(avgLow)
    // is 49.6
    
  3. When to use compose vs. passThrough?

    They can often be used interchangeably. Compose allows you to name a group of functions, which can sometimes be helpful. Other times a name is unnecessary, and you just want to pass data through.