Function
25 exports from @ontologyio/receta/function.
Everything exported from @ontologyio/receta/function. New here? Start with the Function guide.
Functions
ap
Applies an array of functions to an array of values (applicative apply).
Creates all possible combinations by applying each function to each value, returning a flat array of results.
This is useful for applying multiple transformations across multiple values,
though in practice juxt or converge are often more intuitive.
function ap<T, U>(fns: readonly ((value: T) => U)[]): (values: readonly T[]) => U[]function ap<T, U>(fns: readonly ((value: T) => U)[], values: readonly T[]): U[]const fns = [
(n: number) => n + 1,
(n: number) => n * 2,
(n: number) => n * n
]
ap(fns, [1, 2, 3])
// => [
// 2, 3, 4, // addOne to each
// 2, 4, 6, // double each
// 1, 4, 9 // square each
// ]// Apply multiple validators to multiple inputs
const validators = [
(s: string) => s.length > 0,
(s: string) => s.length < 100,
(s: string) => /^[a-z]+$/i.test(s)
]
ap(validators, ['hello', '', 'test123'])
// => [
// true, false, true, // length > 0
// true, true, true, // length < 100
// true, false, false // only letters
// ]// Data-first
const fns = [(n: number) => n + 10, (n: number) => n * 10]
const result = ap(fns, [1, 2, 3])
// => [11, 12, 13, 10, 20, 30]binary
Creates a function that only accepts two arguments, ignoring additional arguments.
This is useful when you want to limit the number of arguments passed to a function in callbacks or higher-order functions.
function binary<A, B, R>(fn: (a: A, b: B, ...rest: any[]) => R): (a: A, b: B) => Rconst add = (...nums: number[]) => nums.reduce((a, b) => a + b, 0)
add(1, 2, 3, 4) // => 10
// reduce also passes the index and the array, which binary drops
const numbers = [1, 2, 3, 4]
numbers.reduce(binary(add)) // => 10// Limiting callback arguments
const logTwo = binary(console.log)
const letters = ['a', 'b', 'c']
letters.forEach(logTwo)
// Logs:
// a 0
// b 1
// c 2
// (ignores array parameter)compose
Composes functions from right to left.
Creates a new function that applies the given functions in reverse order, passing the result of each function as input to the next.
This is the mathematical composition: (f ∘ g)(x) = f(g(x))
Note: For left-to-right composition (more common in data pipelines),
use Remeda's pipe function instead.
function compose<A, B>(fn1: (a: A) => B): (a: A) => Bfunction compose<A, B, C>(fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => Cfunction compose<A, B, C, D>(fn3: (c: C) => D, fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => Dfunction compose<A, B, C, D, E>(fn4: (d: D) => E, fn3: (c: C) => D, fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => Efunction compose<A, B, C, D, E, F>(fn5: (e: E) => F, fn4: (d: D) => E, fn3: (c: C) => D, fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => Fconst addOne = (n: number) => n + 1
const double = (n: number) => n * 2
const square = (n: number) => n * n
const f = compose(square, double, addOne)
f(2) // => square(double(addOne(2))) => square(double(3)) => square(6) => 36// String transformations
const exclaim = (s: string) => `${s}!`
const toUpper = (s: string) => s.toUpperCase()
const trim = (s: string) => s.trim()
const shout = compose(exclaim, toUpper, trim)
shout(' hello ') // => 'HELLO!'// For left-to-right, use pipe instead
import { pipe } from 'remeda'
const result = pipe(
' hello ',
trim,
toUpper,
exclaim
)
// => 'HELLO!'See also https://remedajs.com/docs#pipe.
cond
Creates a function that applies the first matching predicate-function pair.
Returns a function that tests its input against each predicate in order, applying the corresponding function when a match is found. Returns None if no predicates match.
This is like a functional switch statement or if-else chain, useful for multi-way conditional logic with clean, declarative syntax.
function cond<T, U>(pairs: readonly CondPair<T, U>[]): (value: T) => Option<U>function cond<T, U>(pairs: readonly CondPair<T, U>[], value: T): Option<U>const classifyNumber = cond<number, string>([
[(n) => n < 0, (n) => 'negative'],
[(n) => n === 0, () => 'zero'],
[(n) => n > 0 && n < 10, (n) => 'small positive'],
[(n) => n >= 10, (n) => 'large positive']
])
classifyNumber(-5) // => Some('negative')
classifyNumber(0) // => Some('zero')
classifyNumber(3) // => Some('small positive')
classifyNumber(100) // => Some('large positive')// HTTP status code handling
const handleStatus = cond<number, string>([
[(s) => s >= 200 && s < 300, () => 'success'],
[(s) => s >= 300 && s < 400, () => 'redirect'],
[(s) => s >= 400 && s < 500, () => 'client error'],
[(s) => s >= 500, () => 'server error']
])
handleStatus(200) // => Some('success')
handleStatus(404) // => Some('client error')
handleStatus(500) // => Some('server error')// Data-first
const result = cond<string, number>([
[(s) => s === 'low', () => 1],
[(s) => s === 'medium', () => 5],
[(s) => s === 'high', () => 10]
], 'medium')
// => Some(5)converge
Creates a function that applies multiple functions to the same input, then combines their results.
The converge combinator applies each function in the array to the input value,
collecting the results, then passes all results to the after function.
This is useful when you need to derive multiple values from a single input and combine them in some way.
function converge<T, Args extends readonly unknown[], R>(after: (...args: Args) => R, fns: FunctionTuple<T, Args>): (value: T) => Rfunction converge<T, Args extends readonly unknown[], R>(after: (...args: Args) => R, fns: FunctionTuple<T, Args>, value: T): R// Calculate average by dividing sum by length
const average = converge<number[], [number, number], number>(
(sum, length) => sum / length,
[
(nums) => nums.reduce((a, b) => a + b, 0), // sum
(nums) => nums.length // length
]
)
average([1, 2, 3, 4, 5]) // => 3// Build an object from different transformations
interface User { name: string; email: string }
interface Profile { displayName: string; username: string; domain: string }
const buildProfile = converge<User, [string, string, string], Profile>(
(name, username, domain) => ({
displayName: name,
username,
domain
}),
[
(user) => user.name,
(user) => user.email.split('@')[0]!,
(user) => user.email.split('@')[1]!
]
)
buildProfile({ name: 'Alice', email: 'alice@example.com' })
// => { displayName: 'Alice', username: 'alice', domain: 'example.com' }// Data-first
const result = converge(
(min: number, max: number) => max - min,
[
(nums: number[]) => Math.min(...nums),
(nums: number[]) => Math.max(...nums)
],
[1, 5, 3, 9, 2]
)
// => 8 (range from 1 to 9)flip
Creates a function that reverses the order of the first two arguments.
This is useful when you have a function with arguments in an inconvenient order for partial application or piping.
function flip<A, B, R>(fn: (a: A, b: B) => R): (b: B, a: A) => Rfunction flip<A, B, C, R>(fn: (a: A, b: B, c: C) => R): (b: B, a: A, c: C) => Rfunction flip<A, B, C, D, R>(fn: (a: A, b: B, c: C, d: D) => R): (b: B, a: A, c: C, d: D) => Rconst divide = (a: number, b: number) => a / b
const divideBy = flip(divide)
divide(10, 2) // => 5
divideBy(2, 10) // => 5 (same as divide(10, 2))// Useful for partial application
const subtract = (a: number, b: number) => a - b
const subtractFrom = flip(subtract)
const subtractFrom10 = (n: number) => subtractFrom(n, 10)
subtractFrom10(3) // => 7 (10 - 3)// With object methods
const concat = (a: string, b: string) => a + b
const append = flip(concat)
concat('hello', ' world') // => 'hello world'
append(' world', 'hello') // => 'hello world'guard
Validates a value through a series of guard clauses (early return pattern).
Tests the input against each predicate in order. If a predicate returns false, immediately returns Err with the corresponding error. If all predicates pass, returns Ok with the original value.
This implements the guard clause / early return pattern common in validation chains, allowing you to declaratively express a series of validation rules.
function guard<T, E>(pairs: readonly GuardPair<T, E>[]): (value: T) => Result<T, E>function guard<T, E>(pairs: readonly GuardPair<T, E>[], value: T): Result<T, E>// User validation
const validateUser = guard<User, string>([
[(u) => u.age >= 18, 'Must be 18 or older'],
[(u) => u.email.includes('@'), 'Invalid email format'],
[(u) => u.name.trim().length > 0, 'Name is required']
])
validateUser({ age: 25, email: 'test@example.com', name: 'Alice' })
// => Ok({ age: 25, email: 'test@example.com', name: 'Alice' })
validateUser({ age: 16, email: 'test@example.com', name: 'Bob' })
// => Err('Must be 18 or older')
validateUser({ age: 25, email: 'invalid', name: 'Charlie' })
// => Err('Invalid email format')// Data-first
const result = guard<number, string>(
[
[(n) => n > 0, 'Must be positive'],
[(n) => n < 100, 'Must be less than 100'],
[(n) => Number.isInteger(n), 'Must be an integer']
],
42
)
// => Ok(42)import { map } from '@ontologyio/receta/result'
// In a pipe for validation chains
pipe(
parseFormData(),
guard([
[(data) => 'username' in data, 'Username is required'],
[(data) => data.username.length >= 3, 'Username too short']
]),
map(createUser)
)// With structured errors
type ValidationError = { field: string; message: string }
const validatePassword = guard<string, ValidationError>([
[
(pwd) => pwd.length >= 8,
{ field: 'password', message: 'Password must be at least 8 characters' }
],
[
(pwd) => /[A-Z]/.test(pwd),
{ field: 'password', message: 'Password must contain uppercase letter' }
],
[
(pwd) => /[0-9]/.test(pwd),
{ field: 'password', message: 'Password must contain a number' }
]
])See also when, cond.
ifElse
Creates a function that conditionally applies one of two functions based on a predicate.
Returns a function that tests its input against the predicate, then applies
either onTrue if the predicate passes, or onFalse if it fails.
function ifElse<T, U>(predicate: Predicate<T>, onTrue: Mapper<T, U>, onFalse: Mapper<T, U>): (value: T) => Ufunction ifElse<T, U>(predicate: Predicate<T>, onTrue: Mapper<T, U>, onFalse: Mapper<T, U>, value: T): Uconst classify = ifElse(
(n: number) => n >= 0,
(n) => 'positive',
(n) => 'negative'
)
classify(5) // => 'positive'
classify(-3) // => 'negative'
classify(0) // => 'positive'// Data-first signature
const result = ifElse(
(age: number) => age >= 18,
(age) => ({ status: 'adult', age }),
(age) => ({ status: 'minor', age }),
25
)
// => { status: 'adult', age: 25 }// In a pipe
pipe(
fetchUser(),
ifElse(
(user) => user.role === 'admin',
(user) => grantFullAccess(user),
(user) => grantLimitedAccess(user)
)
)juxt
Creates a function that applies multiple functions to the same input and returns all results as an array.
The juxt combinator (short for "juxtaposition") applies each function to the input value
and collects all results in an array, preserving the order.
This is useful when you need to apply multiple transformations to the same value and keep all the results.
function juxt<Fns extends readonly ((...args: any[]) => any)[]>(fns: Fns): (...args: Parameters<Fns[0]>) => ReturnTypes<Fns>function juxt<Fns extends readonly ((...args: any[]) => any)[]>(fns: Fns, ...args: Parameters<Fns[0]>): ReturnTypes<Fns>const analyze = juxt([
(nums: number[]) => nums.length,
(nums: number[]) => Math.min(...nums),
(nums: number[]) => Math.max(...nums),
(nums: number[]) => nums.reduce((a, b) => a + b, 0) / nums.length
])
analyze([1, 2, 3, 4, 5])
// => [5, 1, 5, 3]
// [length, min, max, average]// Extract multiple fields from an object
interface User { id: string; name: string; email: string; role: string }
const getUserSummary = juxt([
(user: User) => user.id,
(user: User) => user.name,
(user: User) => user.role
])
getUserSummary({ id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin' })
// => ['1', 'Alice', 'admin']// Data-first
const result = juxt([
(s: string) => s.toUpperCase(),
(s: string) => s.toLowerCase(),
(s: string) => s.length
], 'Hello')
// => ['HELLO', 'hello', 5]// In a pipe
pipe(
getUserInput(),
juxt([
(input) => input.trim(),
(input) => input.length,
(input) => input.split(' ').length
])
)
// => [trimmedInput, totalLength, wordCount]memoize
Creates a memoized version of a function that caches its results.
This is a simple re-export of the memo module's memoize function,
provided here for convenience in the function module.
By default, uses the first argument as the cache key. For custom cache keys,
use memo.memoizeBy instead.
function memoize<Args extends readonly [unknown, ...unknown[]], R>(fn: (...args: Args) => R, options?: MemoizeOptions<string>): MemoizedFunction<Args, R>const fibonacci = memoize((n: number): number => {
if (n <= 1) return n
return fibonacci(n - 1) + fibonacci(n - 2)
})
fibonacci(40) // Computed once
fibonacci(40) // Returned from cache instantly// Memoizing expensive computations
const expensiveCalc = memoize((data: string) => {
console.log('Computing...')
return data.split('').reverse().join('')
})
expensiveCalc('hello') // Logs "Computing...", returns "olleh"
expensiveCalc('hello') // Returns "olleh" (no log, cached)
expensiveCalc('world') // Logs "Computing...", returns "dlrow"// For custom cache keys, use memo.memoizeBy
import { memoizeBy } from '@ontologyio/receta/memo'
const fetchUser = memoizeBy(
(id: string) => fetch(`/api/users/${id}`).then(r => r.json()),
(id) => id // Cache key function
)See also memo.memoize, memo.memoizeBy, memo.memoizeAsync.
nAry
Creates a function that only accepts N arguments, ignoring additional arguments.
This is the generalized version of unary and binary, allowing you to specify
exactly how many arguments should be accepted.
function nAry<R>(n: number, fn: (...args: any[]) => R): (...args: any[]) => Rconst sum = (...nums: number[]) => nums.reduce((a, b) => a + b, 0)
const sumTwo = nAry(2, sum)
sumTwo(1, 2, 3, 4, 5) // => 3 (only sums first two)
const sumThree = nAry(3, sum)
sumThree(1, 2, 3, 4, 5) // => 6 (only sums first three)// Controlling variadic functions
const max = (...nums: number[]) => Math.max(...nums)
const maxOfTwo = nAry(2, max)
maxOfTwo(5, 10, 2, 8) // => 10 (only considers first two)// Creating specialized versions
const log = (...args: any[]) => console.log(...args)
const logOne = nAry(1, log)
const logThree = nAry(3, log)
logOne('a', 'b', 'c') // Logs: a
logThree('a', 'b', 'c', 'd') // Logs: a b cpartial
Creates a partially applied function by pre-filling arguments from the left.
Returns a new function that, when called, invokes the original function with the pre-filled arguments followed by any new arguments.
function partial<Args extends readonly any[], R>(fn: (...args: Args) => R): (...args: Args) => Rfunction partial<Args extends readonly any[], R>(fn: (...args: Args) => R, ...prefilledArgs: any[]): (...args: any[]) => Rconst greet = (greeting: string, name: string) => `${greeting}, ${name}!`
const sayHello = partial(greet, 'Hello')
sayHello('Alice') // => 'Hello, Alice!'
sayHello('Bob') // => 'Hello, Bob!'// Multiple arguments
const multiply = (a: number, b: number, c: number) => a * b * c
const double = partial(multiply, 2)
double(3, 4) // => 24 (2 * 3 * 4)
const quadruple = partial(multiply, 2, 2)
quadruple(5) // => 20 (2 * 2 * 5)// Creating specialized functions
const log = (level: string, module: string, message: string) =>
`[${level}] ${module}: ${message}`
const logError = partial(log, 'ERROR')
const logUserError = partial(log, 'ERROR', 'UserModule')
logUserError('Invalid input') // => '[ERROR] UserModule: Invalid input'partialRight
Creates a partially applied function by pre-filling arguments from the right.
Returns a new function that, when called, invokes the original function with any new arguments followed by the pre-filled arguments.
This is the mirror of partial, filling arguments from the end instead of the start.
function partialRight<Args extends readonly any[], R>(fn: (...args: Args) => R): (...args: Args) => Rfunction partialRight<Args extends readonly any[], R>(fn: (...args: Args) => R, ...prefilledArgs: any[]): (...args: any[]) => Rconst divide = (a: number, b: number) => a / b
const divideBy10 = partialRight(divide, 10)
divideBy10(100) // => 10 (100 / 10)
divideBy10(50) // => 5 (50 / 10)// Useful when the settings come last
const formatDate = (date: Date, format: string, locale: string) =>
date.toLocaleDateString(locale, { dateStyle: format as any })
const formatInUS = partialRight(formatDate, 'en-US')
const formatInFR = partialRight(formatDate, 'fr-FR')
const launch = new Date('2026-01-22T12:00:00Z')
formatInUS(launch, 'short') // => '1/22/26'
formatInFR(launch, 'short') // => '22/01/2026'// Multiple arguments from the right
const log = (message: string, level: string, timestamp: string) =>
`${timestamp} [${level}] ${message}`
const logNow = partialRight(log, 'INFO', '2026-01-22T10:00:00Z')
logNow('Application started') // => '2026-01-22T10:00:00Z [INFO] Application started'See also partial.
switchCase
Creates a function that applies the first matching predicate-function pair, with a required default.
Similar to cond, but returns a value directly (not wrapped in Option) by requiring
a default value. This guarantees that a value is always returned, making it useful
for exhaustive pattern matching scenarios.
The key difference from cond:
condreturnsOption<U>(can return None if no match)switchCasereturnsU(always returns a value via default)
function switchCase<T, U>(pairs: readonly CondPair<T, U>[], defaultValue: U): (value: T) => Ufunction switchCase<T, U>(pairs: readonly CondPair<T, U>[], defaultValue: U, value: T): U// Priority assignment with default
const getPriority = switchCase<string, number>(
[
[(s) => s === 'critical', () => 1],
[(s) => s === 'high', () => 2],
[(s) => s === 'medium', () => 3],
[(s) => s === 'low', () => 4]
],
5 // default priority for unknown levels
)
getPriority('critical') // => 1
getPriority('high') // => 2
getPriority('unknown') // => 5 (default)// HTTP status handling with default error message
const getStatusMessage = switchCase<number, string>(
[
[(s) => s >= 200 && s < 300, () => 'Success'],
[(s) => s >= 300 && s < 400, () => 'Redirect'],
[(s) => s === 404, () => 'Not Found'],
[(s) => s >= 400 && s < 500, () => 'Client Error'],
[(s) => s >= 500, () => 'Server Error']
],
'Unknown Status'
)
getStatusMessage(200) // => 'Success'
getStatusMessage(404) // => 'Not Found'
getStatusMessage(100) // => 'Unknown Status'// Data-first
const result = switchCase<string, number>(
[
[(s) => s === 'small', () => 10],
[(s) => s === 'medium', () => 20],
[(s) => s === 'large', () => 30]
],
15, // default value
'medium'
)
// => 20// In a pipe
pipe(
getUserRole(),
switchCase<Role, Permissions>(
[
[(r) => r === 'admin', () => allPermissions],
[(r) => r === 'editor', () => editorPermissions],
[(r) => r === 'viewer', () => viewPermissions]
],
noPermissions // default for unknown roles
)
)// File extension to MIME type mapping
const getMimeType = switchCase<string, string>(
[
[(ext) => ext === 'jpg' || ext === 'jpeg', () => 'image/jpeg'],
[(ext) => ext === 'png', () => 'image/png'],
[(ext) => ext === 'gif', () => 'image/gif'],
[(ext) => ext === 'pdf', () => 'application/pdf'],
[(ext) => ext === 'json', () => 'application/json']
],
'application/octet-stream' // default MIME type
)See also cond, ifElse.
tap
Executes a side effect function and returns the original value unchanged.
This is invaluable for debugging pipelines or performing side effects (like logging) without breaking the data flow.
function tap<T>(fn: (value: T) => void): (value: T) => Tfunction tap<T>(fn: (value: T) => void, value: T): T// Debugging a pipeline
pipe(
[1, 2, 3, 4, 5],
R.map(x => x * 2),
tap(x => console.log('After doubling:', x)), // [2, 4, 6, 8, 10]
R.filter(x => x > 5),
tap(x => console.log('After filtering:', x)), // [6, 8, 10]
R.reduce((a, b) => a + b, 0)
)// Data-first
const result = tap(
(x) => console.log('Value:', x),
42
)
// Logs: "Value: 42"
// => 42// Side effects in a chain
const processUser = pipe(
fetchUser(userId),
tap(user => analytics.track('user_fetched', { id: user.id })),
tap(user => logger.info('Processing user', user)),
transformUser,
tap(transformed => cache.set(userId, transformed)),
saveUser
)// Conditional logging
pipe(
getData(),
tap(data => {
if (process.env.NODE_ENV === 'development') {
console.log('Debug:', data)
}
}),
processData
)tryCatch
Wraps a function to safely execute it and return a Result.
This is a convenience wrapper around Result.tryCatch that creates a
function you can reuse, rather than wrapping a single execution.
Note: This wraps the Result module's tryCatch. For one-off executions,
use Result.tryCatch directly.
It only catches synchronous throws. An async function comes back as an Ok
holding its promise, and a rejection isn't caught. Use tryCatchAsync from
the Result module for async code.
function tryCatch<Args extends readonly any[], T, E = unknown>(fn: (...args: Args) => T, onError?: ((error: unknown) => E) | undefined): (...args: Args) => Result<T, E>const parseJSON = tryCatch(
(str: string) => JSON.parse(str),
() => 'Invalid JSON'
)
parseJSON('{"valid": "json"}') // => Ok({ valid: 'json' })
parseJSON('invalid json') // => Err('Invalid JSON')// Creating safe versions of throwing functions
const safeDivide = tryCatch(
(a: number, b: number) => {
if (b === 0) throw new Error('Division by zero')
return a / b
}
)
safeDivide(10, 2) // => Ok(5)
safeDivide(10, 0) // => Err(Error('Division by zero'))import { flatMap, map } from '@ontologyio/receta/result'
// In a pipe with Result operations
pipe(
getUserInput(),
tryCatch((input: string) => JSON.parse(input)),
map(data => data.userId),
flatMap(fetchUser)
)See also Result.tryCatch.
unary
Creates a function that only accepts one argument, ignoring additional arguments.
This is useful when passing functions to higher-order functions that provide multiple arguments, but you only want to use the first one.
function unary<A, R>(fn: (a: A, ...rest: any[]) => R): (a: A) => R// parseInt takes two arguments, which causes issues with map
const digits = ['1', '2', '3']
digits.map(parseInt) // => [1, NaN, NaN]
digits.map(unary(parseInt)) // => [1, 2, 3]const logFirst = unary(console.log)
const letters = ['a', 'b', 'c']
letters.forEach(logFirst)
// Logs:
// a
// b
// c
// (without indices or array)// Wrapping functions for cleaner callbacks
const parseNumber = unary(Number)
const inputs = ['42', '3.14', '100']
inputs.map(parseNumber) // => [42, 3.14, 100]unless
Creates a function that conditionally applies a transformation (inverse of when).
Returns a function that tests its input against the predicate. If the predicate fails, applies the given function; otherwise returns the input unchanged.
This is the inverse of when - it applies the transformation when the
condition is NOT met.
function unless<T>(predicate: Predicate<T>, fn: Mapper<T, T>): (value: T) => Tfunction unless<T>(predicate: Predicate<T>, fn: Mapper<T, T>, value: T): Tconst ensureArray = unless(
Array.isArray,
(value) => [value]
)
ensureArray([1, 2, 3]) // => [1, 2, 3]
ensureArray(5) // => [5]
ensureArray('hello') // => ['hello']// Data-first
const result = unless<string>(
(str) => str.startsWith('http'),
(str) => `https://${str}`,
'example.com'
)
// => 'https://example.com'// In a pipe
pipe(
getConfig(),
unless(
(config) => 'apiKey' in config,
(config) => ({ ...config, apiKey: process.env.API_KEY })
)
)See also when.
when
Creates a function that conditionally applies a transformation.
Returns a function that tests its input against the predicate. If the predicate passes, applies the given function; otherwise returns the input unchanged.
This is useful for conditional transformations where you want to preserve the original value when the condition is not met.
function when<T>(predicate: Predicate<T>, fn: Mapper<T, T>): (value: T) => Tfunction when<T>(predicate: Predicate<T>, fn: Mapper<T, T>, value: T): Tconst ensurePositive = when(
(n: number) => n < 0,
(n) => Math.abs(n)
)
ensurePositive(-5) // => 5
ensurePositive(3) // => 3
ensurePositive(0) // => 0// Data-first
const result = when(
(str: string) => str.length === 0,
() => 'default',
''
)
// => 'default'// In a pipe for conditional transformations
pipe(
getUserInput(),
when(
(input) => input.trim().length === 0,
() => 'Anonymous'
),
processUsername
)See also unless.
Types
CondPair
A pair of predicate and corresponding function for conditional execution.
type CondPair<T, U> = readonly [predicate: Predicate<T>, fn: Mapper<T, U>]FunctionTuple
Represents a tuple of functions that take the same input type.
type FunctionTuple<T, Args extends readonly unknown[]> = {
readonly [K in keyof Args]: Mapper<T, Args[K]>
}GuardPair
A pair of predicate and corresponding error for guard validation.
type GuardPair<T, E> = readonly [predicate: Predicate<T>, error: E]Mapper
A function that transforms a value of type T to type U.
type Mapper<T, U> = (value: T) => UPredicate
A function that takes a value and returns a boolean.
type Predicate<T> = (value: T) => booleanReturnTypes
Extracts the return types of a tuple of functions.
type ReturnTypes<Fns extends readonly ((...args: any[]) => any)[]> = {
readonly [K in keyof Fns]: Fns[K] extends (...args: any[]) => infer R ? R : never
}