Skip to content

chain

Link multiple functions together and execute them in sequence.

Syntax

typescript
chain<T>(
  ...functions: ((value: T) => T)[]
): (value: T) => T

Parameters

  • ...functions (((value: T) => T)[]): Array of functions to chain

Return Value

  • (value: T) => T: The chained function

Examples

Basic Usage

typescript
import { chain } from 'radash'

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

const pipeline = chain(addOne, multiplyByTwo, square)

const result = pipeline(3)
// Steps: 3 -> 4 -> 8 -> 64
// Result: 64

String Processing

typescript
import { chain } from 'radash'

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

const processString = chain(toUpperCase, addExclamation, repeat)

const result = processString('hello')
// Steps: 'hello' -> 'HELLO' -> 'HELLO!' -> 'HELLO!HELLO!'
// Result: 'HELLO!HELLO!'

Array Processing

typescript
import { chain } 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((a, b) => a + b, 0)

const processArray = chain(filterEven, double, sum)

const result = processArray([1, 2, 3, 4, 5, 6])
// Steps: [1,2,3,4,5,6] -> [2,4,6] -> [4,8,12] -> 24
// Result: 24

Object Processing

typescript
import { chain } from 'radash'

const addId = (obj: any) => ({ ...obj, id: Date.now() })
const addTimestamp = (obj: any) => ({ ...obj, timestamp: new Date().toISOString() })
const addStatus = (obj: any) => ({ ...obj, status: 'active' })

const processObject = chain(addId, addTimestamp, addStatus)

const result = processObject({ name: 'Alice', age: 25 })
// Result: { name: 'Alice', age: 25, id: 1234567890, timestamp: '2023-01-01T00:00:00.000Z', status: 'active' }

Type Conversion

typescript
import { chain } from 'radash'

const toString = (num: number) => num.toString()
const addPrefix = (str: string) => 'Number: ' + str
const toUpperCase = (str: string) => str.toUpperCase()

const processNumber = chain(toString, addPrefix, toUpperCase)

const result = processNumber(42)
// Steps: 42 -> '42' -> 'Number: 42' -> 'NUMBER: 42'
// Result: 'NUMBER: 42'

Conditional Processing

typescript
import { chain } from 'radash'

const validateAge = (age: number) => {
  if (age < 0 || age > 120) {
    throw new Error('Invalid age')
  }
  return age
}

const categorizeAge = (age: number) => {
  if (age < 18) return 'minor'
  if (age < 65) return 'adult'
  return 'senior'
}

const addCategory = (category: string) => ({ category })

const processAge = chain(validateAge, categorizeAge, addCategory)

const result = processAge(25)
// Result: { category: 'adult' }

Error Handling

typescript
import { chain } from 'radash'

const safeDivide = (x: number) => {
  if (x === 0) throw new Error('Division by zero')
  return 100 / x
}

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

const processNumber = chain(safeDivide, addOne, multiplyByTwo)

try {
  const result = processNumber(5)
  console.log(result) // 42
} catch (error) {
  console.error('Error:', error.message)
}

try {
  processNumber(0) // Throws error
} catch (error) {
  console.error('Error:', error.message) // 'Division by zero'
}

Async Function Chain

typescript
import { chain } from 'radash'

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

const addTimestamp = (user: any) => ({
  ...user,
  fetchedAt: new Date().toISOString()
})

const addStatus = (user: any) => ({
  ...user,
  status: user.active ? 'active' : 'inactive'
})

// Note: Async functions need special handling
const processUser = async (id: number) => {
  const user = await fetchUser(id)
  return chain(addTimestamp, addStatus)(user)
}

// Usage
processUser(123).then(result => {
  console.log(result)
})

Data Validation Chain

typescript
import { chain } from 'radash'

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

const validateLength = (email: string) => {
  if (email.length < 5) {
    throw new Error('Email too short')
  }
  return email
}

const addDomain = (email: string) => {
  if (!email.includes('.')) {
    return email + '.com'
  }
  return email
}

const processEmail = chain(validateEmail, validateLength, addDomain)

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

Configuration Processing

typescript
import { chain } from 'radash'

const setDefaults = (config: any) => ({
  port: 3000,
  host: 'localhost',
  debug: false,
  ...config
})

const validateConfig = (config: any) => {
  if (config.port < 1 || config.port > 65535) {
    throw new Error('Invalid port number')
  }
  return config
}

const addTimestamp = (config: any) => ({
  ...config,
  createdAt: new Date().toISOString()
})

const processConfig = chain(setDefaults, validateConfig, addTimestamp)

const result = processConfig({ port: 8080, debug: true })
// Result: { port: 8080, host: 'localhost', debug: true, createdAt: '2023-01-01T00:00:00.000Z' }

Text Processing Pipeline

typescript
import { chain } from 'radash'

const trim = (str: string) => str.trim()
const toLowerCase = (str: string) => str.toLowerCase()
const removeSpecialChars = (str: string) => str.replace(/[^a-z0-9\s]/g, '')
const normalizeSpaces = (str: string) => str.replace(/\s+/g, ' ')

const normalizeText = chain(trim, toLowerCase, removeSpecialChars, normalizeSpaces)

const result = normalizeText('  Hello, World!  ')
// Steps: '  Hello, World!  ' -> 'Hello, World!' -> 'hello, world!' -> 'hello world' -> 'hello world'
// Result: 'hello world'

Notes

  1. Function order: Functions are executed from left to right
  2. Type safety: All functions must accept and return the same type
  3. Error handling: Any function in the chain that throws an error will interrupt execution
  4. Performance: Each function creates a new value, does not modify the original value

Differences from Other Functions

  • chain: Links multiple functions together
  • compose: Composes functions from right to left
  • pipe: Composes functions from left to right
  • flow: Similar functionality, but may have different implementation

Performance

  • Time Complexity: O(n), where n is the number of functions
  • Space Complexity: O(n)
  • Use Cases: Data processing pipelines, function composition

Released under the MIT License.