Skip to content

partob

Convert partial function parameters to object parameters, supporting parameter binding and currying.

Basic Usage

typescript
import { partob } from 'radash'

const add = (a: number, b: number) => a + b
const addWithObj = partob(add, { a: 5 })

console.log(addWithObj({ b: 3 })) // 8

Syntax

typescript
function partob<T extends (...args: any[]) => any>(
  fn: T,
  partialArgs: Record<string, any>
): (remainingArgs: Record<string, any>) => ReturnType<T>

Parameters

  • fn (function): The function to partially objectify
  • partialArgs (object): Partial arguments to bind

Return Value

Returns a function that accepts the remaining arguments as an object.

Examples

Basic Partial Objectification

typescript
import { partob } from 'radash'

const multiply = (a: number, b: number) => a * b
const multiplyByTwo = partob(multiply, { a: 2 })

console.log(multiplyByTwo({ b: 5 })) // 10
console.log(multiplyByTwo({ b: 10 })) // 20

Multiple Parameter Binding

typescript
import { partob } from 'radash'

const createUser = (name: string, age: number, email: string) => ({
  name,
  age,
  email,
  id: Date.now()
})

const createAdultUser = partob(createUser, { age: 18 })

console.log(createAdultUser({ name: 'Alice', email: 'alice@example.com' }))
// { name: 'Alice', age: 18, email: 'alice@example.com', id: 1234567890 }

Complex Object Parameters

typescript
import { partob } from 'radash'

const processConfig = (baseUrl: string, timeout: number, retries: number, headers: Record<string, string>) => ({
  baseUrl,
  timeout,
  retries,
  headers,
  createdAt: new Date()
})

const createApiConfig = partob(processConfig, { 
  timeout: 5000, 
  retries: 3 
})

const config = createApiConfig({ 
  baseUrl: 'https://api.example.com', 
  headers: { 'Authorization': 'Bearer token' } 
})

console.log(config)

Function with Default Values

typescript
import { partob } from 'radash'

const formatMessage = (message: string, prefix: string, suffix: string) => 
  `${prefix}${message}${suffix}`

const formatWithDefaults = partob(formatMessage, { 
  prefix: '[INFO] ', 
  suffix: '!' 
})

console.log(formatWithDefaults({ message: 'Hello World' }))
// '[INFO] Hello World!'

Async Function Partial Objectification

typescript
import { partob } from 'radash'

const fetchData = async (url: string, method: string, headers: Record<string, string>) => {
  const response = await fetch(url, { method, headers })
  return response.json()
}

const fetchWithDefaults = partob(fetchData, { 
  method: 'GET', 
  headers: { 'Content-Type': 'application/json' } 
})

const data = await fetchWithDefaults({ url: 'https://api.example.com/data' })
console.log(data)

Conditional Parameter Binding

typescript
import { partob } from 'radash'

const validateUser = (name: string, age: number, email: string, strict: boolean) => {
  const errors = []
  
  if (!name) errors.push('Name is required')
  if (age < 0) errors.push('Age must be positive')
  if (!email.includes('@')) errors.push('Invalid email')
  
  if (strict && errors.length > 0) {
    throw new Error(errors.join(', '))
  }
  
  return { name, age, email, valid: errors.length === 0 }
}

const validateStrict = partob(validateUser, { strict: true })
const validateLenient = partob(validateUser, { strict: false })

try {
  const result = validateStrict({ name: 'Alice', age: 25, email: 'alice@example.com' })
  console.log('Strict validation:', result)
} catch (error) {
  console.error('Validation failed:', error.message)
}

const lenientResult = validateLenient({ name: 'Bob', age: -5, email: 'invalid' })
console.log('Lenient validation:', lenientResult)

Mathematical Operations

typescript
import { partob } from 'radash'

const calculate = (operation: string, a: number, b: number) => {
  switch (operation) {
    case 'add': return a + b
    case 'subtract': return a - b
    case 'multiply': return a * b
    case 'divide': return a / b
    default: return 0
  }
}

const add = partob(calculate, { operation: 'add' })
const multiply = partob(calculate, { operation: 'multiply' })

console.log(add({ a: 5, b: 3 })) // 8
console.log(multiply({ a: 4, b: 6 })) // 24

Configuration Objects

typescript
import { partob } from 'radash'

const createLogger = (level: string, format: string, output: string) => ({
  level,
  format,
  output,
  log: (message: string) => console.log(`[${level}] ${message}`)
})

const createInfoLogger = partob(createLogger, { 
  level: 'INFO', 
  format: 'text' 
})

const logger = createInfoLogger({ output: 'console' })
logger.log('Application started')

API Request Builder

typescript
import { partob } from 'radash'

const makeRequest = async (url: string, method: string, headers: Record<string, string>, body?: any) => {
  const response = await fetch(url, {
    method,
    headers,
    body: body ? JSON.stringify(body) : undefined
  })
  return response.json()
}

const createApiClient = partob(makeRequest, { 
  method: 'GET', 
  headers: { 'Content-Type': 'application/json' } 
})

const getUser = createApiClient({ url: 'https://api.example.com/users/1' })
const createUser = partob(makeRequest, { 
  method: 'POST', 
  headers: { 'Content-Type': 'application/json' } 
})({ url: 'https://api.example.com/users' })

// Usage
const user = await getUser
const newUser = await createUser({ body: { name: 'Alice', email: 'alice@example.com' } })

Form Validation

typescript
import { partob } from 'radash'

const validateField = (value: string, minLength: number, maxLength: number, pattern?: RegExp) => {
  const errors = []
  
  if (value.length < minLength) {
    errors.push(`Minimum length is ${minLength}`)
  }
  
  if (value.length > maxLength) {
    errors.push(`Maximum length is ${maxLength}`)
  }
  
  if (pattern && !pattern.test(value)) {
    errors.push('Invalid format')
  }
  
  return { value, valid: errors.length === 0, errors }
}

const validateUsername = partob(validateField, { 
  minLength: 3, 
  maxLength: 20, 
  pattern: /^[a-zA-Z0-9_]+$/ 
})

const validateEmail = partob(validateField, { 
  minLength: 5, 
  maxLength: 100, 
  pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ 
})

console.log(validateUsername({ value: 'john_doe' })) // { value: 'john_doe', valid: true, errors: [] }
console.log(validateEmail({ value: 'invalid-email' })) // { value: 'invalid-email', valid: false, errors: ['Invalid format'] }

Database Query Builder

typescript
import { partob } from 'radash'

const buildQuery = (table: string, select: string[], where: Record<string, any>, orderBy?: string) => ({
  sql: `SELECT ${select.join(', ')} FROM ${table} WHERE ${Object.entries(where).map(([k, v]) => `${k} = '${v}'`).join(' AND ')}${orderBy ? ` ORDER BY ${orderBy}` : ''}`,
  params: where
})

const queryUsers = partob(buildQuery, { 
  table: 'users', 
  select: ['id', 'name', 'email'] 
})

const queryActiveUsers = partob(buildQuery, { 
  table: 'users', 
  select: ['id', 'name', 'email'], 
  where: { status: 'active' } 
})

console.log(queryUsers({ where: { age: 25 } }))
console.log(queryActiveUsers({ orderBy: 'name' }))

Notes

  1. Parameter binding: Binds specific parameters to create specialized functions
  2. Object parameters: Remaining parameters are passed as objects
  3. Type safety: Maintains TypeScript type safety
  4. Flexibility: Allows dynamic parameter binding
  5. Composition: Can be composed with other functional utilities

Differences from Other Methods

  • partob: Converts function parameters to object parameters
  • partial: Binds parameters in order
  • curry: Creates curried functions
  • partob(): More flexible parameter binding with objects

Performance

  • Time Complexity: O(1) for parameter binding
  • Memory: Minimal overhead for function wrapping
  • Use Cases: API clients, configuration builders, form validation

Released under the MIT License.