Skip to content

compose

组合多个函数,创建函数管道。

基础用法

typescript
import { compose } from 'radash'

const addOne = (x: number) => x + 1
const double = (x: number) => x * 2
const square = (x: number) => x * x

const composed = compose(addOne, double, square)
const result = composed(3)
// 计算过程: square(3) = 9, double(9) = 18, addOne(18) = 19
console.log(result) // 19

语法

typescript
function compose<T extends any[], U>(
  ...fns: ((...args: T) => U)[]
): (...args: T) => U

参数

  • ...fns (function[]): 要组合的函数数组

返回值

返回一个组合后的函数,从右到左执行。

示例

基本函数组合

typescript
import { compose } from 'radash'

const toUpperCase = (str: string) => str.toUpperCase()
const addExclamation = (str: string) => str + '!'
const repeat = (str: string) => str + str

const shout = compose(addExclamation, toUpperCase, repeat)
const result = shout('hello')
// 计算过程: repeat('hello') = 'hellohello', toUpperCase('hellohello') = 'HELLOHELLO', addExclamation('HELLOHELLO') = 'HELLOHELLO!'
console.log(result) // 'HELLOHELLO!'

处理数组

typescript
import { compose } from 'radash'

const filterEven = (arr: number[]) => arr.filter(x => x % 2 === 0)
const double = (arr: number[]) => arr.map(x => x * 2)
const sum = (arr: number[]) => arr.reduce((acc, x) => acc + x, 0)

const processNumbers = compose(sum, double, filterEven)
const result = processNumbers([1, 2, 3, 4, 5, 6])
// 计算过程: filterEven([1,2,3,4,5,6]) = [2,4,6], double([2,4,6]) = [4,8,12], sum([4,8,12]) = 24
console.log(result) // 24

处理对象

typescript
import { compose } from 'radash'

const getUsers = (data: any) => data.users
const filterActive = (users: any[]) => users.filter(user => user.active)
const mapNames = (users: any[]) => users.map(user => user.name)
const joinNames = (names: string[]) => names.join(', ')

const getActiveUserNames = compose(joinNames, mapNames, filterActive, getUsers)

const data = {
  users: [
    { id: 1, name: 'Alice', active: true },
    { id: 2, name: 'Bob', active: false },
    { id: 3, name: 'Charlie', active: true },
    { id: 4, name: 'Diana', active: true }
  ]
}

const result = getActiveUserNames(data)
console.log(result) // 'Alice, Charlie, Diana'

处理字符串

typescript
import { compose } from 'radash'

const trim = (str: string) => str.trim()
const toLowerCase = (str: string) => str.toLowerCase()
const replaceSpaces = (str: string) => str.replace(/\s+/g, '-')
const addPrefix = (str: string) => `slug-${str}`

const createSlug = compose(addPrefix, replaceSpaces, toLowerCase, trim)

const result = createSlug('  Hello World  ')
// 计算过程: trim('  Hello World  ') = 'Hello World', toLowerCase('Hello World') = 'hello world', replaceSpaces('hello world') = 'hello-world', addPrefix('hello-world') = 'slug-hello-world'
console.log(result) // 'slug-hello-world'

处理数字

typescript
import { compose } from 'radash'

const add = (a: number) => (b: number) => a + b
const multiply = (a: number) => (b: number) => a * b
const square = (x: number) => x * x

const complexCalculation = compose(
  square,
  multiply(3),
  add(5)
)

const result = complexCalculation(2)
// 计算过程: add(5)(2) = 7, multiply(3)(7) = 21, square(21) = 441
console.log(result) // 441

处理类型转换

typescript
import { compose } from 'radash'

const parseNumber = (str: string) => parseInt(str, 10)
const addTen = (num: number) => num + 10
const double = (num: number) => num * 2
const toString = (num: number) => num.toString()

const processString = compose(toString, double, addTen, parseNumber)

const result = processString('15')
// 计算过程: parseNumber('15') = 15, addTen(15) = 25, double(25) = 50, toString(50) = '50'
console.log(result) // '50'

处理验证和转换

typescript
import { compose } from 'radash'

const validateEmail = (email: string) => {
  if (!email.includes('@')) {
    throw new Error('Invalid email')
  }
  return email
}

const normalizeEmail = (email: string) => email.toLowerCase().trim()
const addDomain = (email: string) => email.includes('@') ? email : email + '@example.com'

const processEmail = compose(addDomain, normalizeEmail, validateEmail)

try {
  const result = processEmail('  USER@EXAMPLE.COM  ')
  console.log(result) // 'user@example.com'
} catch (error) {
  console.error('Error:', error.message)
}

处理异步函数

typescript
import { compose } from 'radash'

const fetchUser = async (id: number) => {
  const response = await fetch(`/api/users/${id}`)
  return response.json()
}

const extractName = (user: any) => user.name
const toUpperCase = (name: string) => name.toUpperCase()

const getUserName = compose(toUpperCase, extractName, fetchUser)

// 注意:由于fetchUser是异步的,这个组合函数也会返回Promise
const result = await getUserName(1)
console.log(result) // 'ALICE'

处理条件逻辑

typescript
import { compose } from 'radash'

const isEven = (num: number) => num % 2 === 0
const double = (num: number) => num * 2
const addOne = (num: number) => num + 1

const processNumber = compose(
  (num: number) => isEven(num) ? double(num) : addOne(num),
  (num: number) => num * 3
)

console.log(processNumber(4)) // 24 (4是偶数,double(4)=8, 8*3=24)
console.log(processNumber(5)) // 18 (5是奇数,addOne(5)=6, 6*3=18)

处理错误处理

typescript
import { compose } from 'radash'

const safeParse = (str: string) => {
  try {
    return JSON.parse(str)
  } catch {
    return null
  }
}

const extractName = (data: any) => data?.name || 'Unknown'
const toUpperCase = (name: string) => name.toUpperCase()

const processData = compose(toUpperCase, extractName, safeParse)

console.log(processData('{"name": "alice"}')) // 'ALICE'
console.log(processData('invalid json')) // 'UNKNOWN'

处理管道操作

typescript
import { compose } from 'radash'

const filterNumbers = (arr: any[]) => arr.filter(x => typeof x === 'number')
const double = (arr: number[]) => arr.map(x => x * 2)
const sum = (arr: number[]) => arr.reduce((acc, x) => acc + x, 0)
const formatResult = (num: number) => `Total: ${num}`

const processArray = compose(formatResult, sum, double, filterNumbers)

const mixedArray = [1, 'hello', 2, 'world', 3, true, 4]
const result = processArray(mixedArray)
// 计算过程: filterNumbers([1,'hello',2,'world',3,true,4]) = [1,2,3,4], double([1,2,3,4]) = [2,4,6,8], sum([2,4,6,8]) = 20, formatResult(20) = 'Total: 20'
console.log(result) // 'Total: 20'

处理复杂对象转换

typescript
import { compose } from 'radash'

interface User {
  id: number
  name: string
  email: string
  age: number
}

const getUsers = (data: any) => data.users || []
const filterAdults = (users: User[]) => users.filter(user => user.age >= 18)
const mapNames = (users: User[]) => users.map(user => user.name)
const sortNames = (names: string[]) => names.sort()
const joinNames = (names: string[]) => names.join(', ')

const getAdultUserNames = compose(joinNames, sortNames, mapNames, filterAdults, getUsers)

const data = {
  users: [
    { id: 1, name: 'Alice', email: 'alice@example.com', age: 25 },
    { id: 2, name: 'Bob', email: 'bob@example.com', age: 16 },
    { id: 3, name: 'Charlie', email: 'charlie@example.com', age: 30 },
    { id: 4, name: 'Diana', email: 'diana@example.com', age: 22 }
  ]
}

const result = getAdultUserNames(data)
console.log(result) // 'Alice, Charlie, Diana'

处理数学计算

typescript
import { compose } from 'radash'

const add = (a: number) => (b: number) => a + b
const multiply = (a: number) => (b: number) => a * b
const subtract = (a: number) => (b: number) => b - a
const square = (x: number) => x * x

const complexMath = compose(
  square,
  multiply(2),
  add(10),
  subtract(5)
)

const result = complexMath(3)
// 计算过程: subtract(5)(3) = -2, add(10)(-2) = 8, multiply(2)(8) = 16, square(16) = 256
console.log(result) // 256

注意事项

  1. 执行顺序: 函数从右到左执行
  2. 类型安全: 确保函数参数和返回值类型匹配
  3. 性能: 组合函数会创建新的函数,注意内存使用
  4. 调试: 组合函数可能难以调试,建议添加日志
  5. 错误处理: 确保中间函数能正确处理错误

与其他方法的区别

  • pipe(): 从左到右执行函数
  • compose(): 从右到左执行函数
  • 手动调用: 需要嵌套函数调用

实际应用场景

  1. 数据处理: 组合多个数据转换步骤
  2. 字符串处理: 组合多个字符串操作
  3. 数学计算: 组合多个数学运算
  4. 验证逻辑: 组合多个验证步骤
  5. 格式化: 组合多个格式化操作

Released under the MIT License.