receta

Predicate

46 exports from @ontologyio/receta/predicate.

Everything exported from @ontologyio/receta/predicate. New here? Start with the Predicate guide.

Functions

always

Creates a predicate that always returns true.

Useful as a default or fallback predicate.

Signature
function always<T>(): Predicate<T>
Example
import * as R from 'remeda'
import { always } from '@ontologyio/receta/predicate'

// Keep all items
R.filter([1, 2, 3], always()) // => [1, 2, 3]

// Real-world: Default case in conditional filtering
const shouldFilter = Math.random() > 0.5
const predicate = shouldFilter ? (n: number) => n > 5 : always<number>()
R.filter([1, 5, 10], predicate)

See also never.

and

Combines multiple predicates with logical AND.

Returns a predicate that is true only if all predicates return true. Short-circuits on the first false result.

Overload 1
function and<T, A extends T, B extends T>(first: TypePredicate<T, A>, second: TypePredicate<T, B>): TypePredicate<T, A & B>
Overload 2
function and<T, A extends T, B extends T, C extends T>(first: TypePredicate<T, A>, second: TypePredicate<T, B>, third: TypePredicate<T, C>): TypePredicate<T, A & B & C>
Overload 3
function and<T>(...predicates: Predicate<T>[]): Predicate<T>
Example
import * as R from 'remeda'
import { gt, lt, and } from '@ontologyio/receta/predicate'

// Combine comparisons
const numbers = [1, 5, 10, 15, 20]
R.filter(numbers, and(gt(5), lt(15))) // => [10]

// Multiple conditions
const users = [
  { age: 25, active: true, verified: true },
  { age: 30, active: false, verified: true },
  { age: 35, active: true, verified: false }
]
R.filter(
  users,
  and(
    (u) => u.age >= 25,
    (u) => u.active,
    (u) => u.verified
  )
) // => [{ age: 25, active: true, verified: true }]

See also or, not.

between

Creates a predicate that tests if a value is within a range (inclusive).

Overload 1
function between(min: number, max: number): Predicate<number>
Overload 2
function between(min: bigint, max: bigint): Predicate<bigint>
Overload 3
function between<T extends number | bigint>(min: T, max: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 5, 10, 15, 20, 25]
R.filter(numbers, between(10, 20)) // => [10, 15, 20]

// Real-world: Filter products by price range
const products = [
  { name: 'Budget', price: 5 },
  { name: 'Standard', price: 15 },
  { name: 'Premium', price: 50 }
]
R.filter(products, (p) => between(10, 30)(p.price))
// => [{ name: 'Standard', price: 15 }]

See also gt, lt.

by

Creates a predicate by composing a selector function with a predicate.

Useful for testing derived values or nested properties.

Signature
function by<T, U>(selector: (value: T) => U, predicate: Predicate<U>): Predicate<T>
Example
import * as R from 'remeda'
import { by, gt } from '@ontologyio/receta/predicate'

const users = [
  { name: 'Alice', tags: ['admin', 'user'] },
  { name: 'Bob', tags: ['user'] },
  { name: 'Charlie', tags: ['admin', 'moderator', 'user'] }
]

// Test derived values
R.filter(
  users,
  by((u) => u.tags.length, gt(1))
)
// => Alice and Charlie (have multiple tags)

// Real-world: Filter by computed values
const products = [
  { name: 'A', price: 100, discount: 0.1 },
  { name: 'B', price: 50, discount: 0.2 },
  { name: 'C', price: 150, discount: 0 }
]
R.filter(
  products,
  by((p) => p.price * (1 - p.discount), gt(80))
)
// => products with final price > 80

See also prop, where.

endsWith

Creates a predicate that tests if a string ends with a suffix.

Case-sensitive.

Signature
function endsWith(suffix: string): Predicate<string>
Example
import * as R from 'remeda'

const files = ['app.ts', 'app.js', 'config.json', 'test.spec.ts']
R.filter(files, endsWith('.ts')) // => ['app.ts', 'test.spec.ts']

See also startsWith, includes.

eq

Creates a predicate that tests if a value equals another value.

Uses strict equality (===).

Signature
function eq<T>(expected: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 2, 3, 2, 1]
R.filter(numbers, eq(2)) // => [2, 2]

const users = [
  { id: 1, status: 'active' },
  { id: 2, status: 'inactive' },
  { id: 3, status: 'active' }
]
R.filter(users, (u) => eq('active')(u.status)) // => active users

See also neq.

gt

Creates a predicate that tests if a value is greater than a threshold.

Overload 1
function gt(threshold: number): Predicate<number>
Overload 2
function gt(threshold: bigint): Predicate<bigint>
Overload 3
function gt<T extends number | bigint>(threshold: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 5, 10, 15, 20]
R.filter(numbers, gt(10)) // => [15, 20]

// With pipe
R.pipe(
  numbers,
  R.filter(gt(10))
) // => [15, 20]

See also gte, lt, between.

gte

Creates a predicate that tests if a value is greater than or equal to a threshold.

Overload 1
function gte(threshold: number): Predicate<number>
Overload 2
function gte(threshold: bigint): Predicate<bigint>
Overload 3
function gte<T extends number | bigint>(threshold: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 5, 10, 15, 20]
R.filter(numbers, gte(10)) // => [10, 15, 20]

See also gt, lte.

hasProperty

Creates a predicate that tests if an object has a specific property.

Signature
function hasProperty<T extends object, K extends string>(key: K): Predicate<T>
Example
import * as R from 'remeda'
import { hasProperty } from '@ontologyio/receta/predicate'

const objects = [
  { name: 'Alice', age: 25 },
  { name: 'Bob' },
  { name: 'Charlie', age: 30 }
]

R.filter(objects, hasProperty('age'))
// => [{ name: 'Alice', age: 25 }, { name: 'Charlie', age: 30 }]

// Real-world: Filter objects with optional properties
const users = [
  { id: 1, email: 'alice@example.com' },
  { id: 2 },
  { id: 3, email: 'charlie@example.com' }
]
R.filter(users, hasProperty('email')) // => users with email

See also prop, where.

includes

Creates a predicate that tests if a string contains a substring.

Case-sensitive.

Signature
function includes(substring: string): Predicate<string>
Example
import * as R from 'remeda'

const emails = ['alice@gmail.com', 'bob@yahoo.com', 'charlie@gmail.com']
R.filter(emails, includes('@gmail.com')) // => Gmail emails

// Real-world: Search functionality
const users = [
  { name: 'Alice Smith' },
  { name: 'Bob Johnson' },
  { name: 'Alice Brown' }
]
const searchTerm = 'Smith'
R.filter(users, (u) => includes(searchTerm)(u.name))
// => [{ name: 'Alice Smith' }]

See also startsWith, endsWith.

isArray

Type guard that checks if a value is an array.

Signature
function isArray(value: unknown): value is unknown[]
Example
import { isArray } from '@ontologyio/receta/predicate'

const value: unknown = [1, 2, 3]
if (isArray(value)) {
  console.log(value.length) // TypeScript knows value is array
}

See also isObject, isFunction.

isBoolean

Type guard that checks if a value is a boolean.

Narrows the type to boolean in TypeScript.

Signature
function isBoolean(value: unknown): value is boolean
Example
import * as R from 'remeda'
import { isBoolean } from '@ontologyio/receta/predicate'

const mixed: unknown[] = [true, 1, false, 'yes']
const booleans = R.filter(mixed, isBoolean) // type: boolean[]
// => [true, false]

See also isString, isNumber.

isDate

Type guard that checks if a value is a Date instance.

Signature
function isDate(value: unknown): value is Date
Example
import { isDate } from '@ontologyio/receta/predicate'

isDate(new Date()) // => true
isDate('2024-01-01') // => false
isDate(Date.now()) // => false

isDefined

Type guard that checks if a value is not null or undefined.

Narrows out null and undefined from the type.

Signature
function isDefined<T>(value: T): value is NonNullable<T>
Example
import * as R from 'remeda'
import { isDefined } from '@ontologyio/receta/predicate'

const values: Array<string | null | undefined> = ['hello', null, 'world', undefined]
const defined = R.filter(values, isDefined) // type: string[]
// => ['hello', 'world']

See also isNullish.

isEmpty

A predicate that tests if a value is empty.

Works with strings, arrays, and objects.

  • Strings: empty if length === 0
  • Arrays: empty if length === 0
  • Objects: empty if has no own properties
Signature
function isEmpty(value: string | readonly unknown[] | Record<string, unknown>): boolean
Example
import * as R from 'remeda'

R.filter(['', 'hello', '', 'world'], isEmpty) // => ['', '']
R.filter([[], [1, 2], []], isEmpty) // => [[], []]
R.filter([{}, { a: 1 }, {}], isEmpty) // => [{}, {}]

// Real-world: Remove empty form fields
const formData = { name: 'Alice', email: '', bio: 'Developer' }
R.pipe(
  R.entries(formData),
  R.filter(([_, value]) => !isEmpty(value)),
  R.fromEntries
) // => { name: 'Alice', bio: 'Developer' }

See also isNotEmpty.

isError

Type guard that checks if a value is an Error instance.

Signature
function isError(value: unknown): value is Error
Example
import { isError } from '@ontologyio/receta/predicate'

isError(new Error('fail')) // => true
isError(new TypeError('invalid')) // => true
isError('error message') // => false

isFiniteNumber

Type guard that checks if a value is a finite number.

Returns false for Infinity, -Infinity, and NaN.

Signature
function isFiniteNumber(value: unknown): value is number
Example
import { isFiniteNumber } from '@ontologyio/receta/predicate'

isFiniteNumber(42) // => true
isFiniteNumber(Infinity) // => false
isFiniteNumber(-Infinity) // => false
isFiniteNumber(NaN) // => false

See also isNumber, isInteger.

isFunction

Type guard that checks if a value is a function.

Signature
function isFunction(value: unknown): value is Function
Example
import * as R from 'remeda'
import { isFunction } from '@ontologyio/receta/predicate'

const mixed: unknown[] = [() => {}, 42, function() {}, 'test']
R.filter(mixed, isFunction) // type: Function[]

See also isObject, isArray.

isInstanceOf

Creates a type guard that checks if a value is an instance of a class.

Signature
function isInstanceOf<T>(constructor: new (...args: any[]) => T): TypePredicate<unknown, T>
Example
import * as R from 'remeda'
import { isInstanceOf } from '@ontologyio/receta/predicate'

class User {
  constructor(public name: string) {}
}

const values: unknown[] = [
  new User('Alice'),
  { name: 'Bob' },
  new User('Charlie')
]
const users = R.filter(values, isInstanceOf(User)) // type: User[]
// => [User('Alice'), User('Charlie')]

isInteger

Type guard that checks if a value is an integer.

Signature
function isInteger(value: unknown): value is number
Example
import * as R from 'remeda'
import { isInteger } from '@ontologyio/receta/predicate'

const numbers = [1, 1.5, 2, 2.5, 3]
R.filter(numbers, isInteger) // => [1, 2, 3]

See also isNumber, isFiniteNumber.

isNotEmpty

A predicate that tests if a value is not empty.

The inverse of isEmpty.

Signature
function isNotEmpty(value: string | readonly unknown[] | Record<string, unknown>): boolean
Example
import * as R from 'remeda'

R.filter(['', 'hello', '', 'world'], isNotEmpty) // => ['hello', 'world']

See also isEmpty.

isNull

Type guard that checks if a value is null.

Signature
function isNull(value: unknown): value is null
Example
import * as R from 'remeda'
import { isNull } from '@ontologyio/receta/predicate'

const values: unknown[] = [null, undefined, 0, '']
R.filter(values, isNull) // => [null]

See also isUndefined, isNullish, isDefined.

isNullish

Type guard that checks if a value is null or undefined.

Signature
function isNullish(value: unknown): value is null | undefined
Example
import * as R from 'remeda'
import { isNullish, not } from '@ontologyio/receta/predicate'

const values: Array<string | null | undefined> = ['hello', null, 'world', undefined]
R.filter(values, not(isNullish)) // type stays (string | null | undefined)[]. isDefined narrows it
// => ['hello', 'world']

See also isDefined, isNull, isUndefined.

isNumber

Type guard that checks if a value is a number.

Narrows the type to number in TypeScript. Returns false for NaN. Infinity passes: use isFiniteNumber to reject it too.

Signature
function isNumber(value: unknown): value is number
Example
import * as R from 'remeda'
import { isNumber } from '@ontologyio/receta/predicate'

const mixed: unknown[] = [42, 'hello', 100, null]
const numbers = R.filter(mixed, isNumber) // type: number[]
// => [42, 100]

// Type narrowing
const value: unknown = 42
if (isNumber(value)) {
  console.log(value * 2) // TypeScript knows value is number
}

See also isFiniteNumber, isInteger, isString.

isObject

Type guard that checks if a value is a non-null object that isn't an array.

Returns false for arrays, functions and null. Class instances such as Date and Map pass.

Signature
function isObject(value: unknown): value is Record<string, unknown>
Example
import { isObject } from '@ontologyio/receta/predicate'

isObject({}) // => true
isObject({ a: 1 }) // => true
isObject([]) // => false
isObject(null) // => false
isObject(() => {}) // => false

See also isArray, isFunction.

isPromise

Type guard that checks if a value is a Promise.

Signature
function isPromise(value: unknown): value is Promise<unknown>
Example
import { isPromise } from '@ontologyio/receta/predicate'

isPromise(Promise.resolve(42)) // => true
isPromise(async () => {}) // => false (it's a function)
await isPromise((async () => {})()) // => true (result of calling it)

isRegExp

Type guard that checks if a value is a RegExp instance.

Signature
function isRegExp(value: unknown): value is RegExp
Example
import { isRegExp } from '@ontologyio/receta/predicate'

isRegExp(/test/) // => true
isRegExp(new RegExp('test')) // => true
isRegExp('/test/') // => false

isString

Type guard that checks if a value is a string.

Narrows the type to string in TypeScript.

Signature
function isString(value: unknown): value is string
Example
import * as R from 'remeda'
import { isString } from '@ontologyio/receta/predicate'

const mixed: unknown[] = ['hello', 42, 'world', true]
const strings = R.filter(mixed, isString) // type: string[]
// => ['hello', 'world']

// Type narrowing in conditionals
const value: unknown = 'test'
if (isString(value)) {
  console.log(value.toUpperCase()) // TypeScript knows value is string
}

See also isNumber, isBoolean.

isUndefined

Type guard that checks if a value is undefined.

Signature
function isUndefined(value: unknown): value is undefined
Example
import * as R from 'remeda'
import { isUndefined } from '@ontologyio/receta/predicate'

const values: unknown[] = [null, undefined, 0, '']
R.filter(values, isUndefined) // => [undefined]

See also isNull, isNullish, isDefined.

lt

Creates a predicate that tests if a value is less than a threshold.

Overload 1
function lt(threshold: number): Predicate<number>
Overload 2
function lt(threshold: bigint): Predicate<bigint>
Overload 3
function lt<T extends number | bigint>(threshold: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 5, 10, 15, 20]
R.filter(numbers, lt(10)) // => [1, 5]

// Useful for filtering by age, price, etc.
const products = [
  { name: 'A', price: 5 },
  { name: 'B', price: 15 },
  { name: 'C', price: 25 }
]
R.filter(products, (p) => lt(20)(p.price)) // => products A and B

See also lte, gt, between.

lte

Creates a predicate that tests if a value is less than or equal to a threshold.

Overload 1
function lte(threshold: number): Predicate<number>
Overload 2
function lte(threshold: bigint): Predicate<bigint>
Overload 3
function lte<T extends number | bigint>(threshold: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 5, 10, 15, 20]
R.filter(numbers, lte(10)) // => [1, 5, 10]

See also lt, gte.

matches

Creates a predicate that tests if a string matches a regular expression.

Signature
function matches(pattern: RegExp): Predicate<string>
Example
import * as R from 'remeda'

const emails = ['alice@example.com', 'invalid-email', 'bob@test.org']
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
R.filter(emails, matches(emailPattern)) // => valid emails

// Real-world: Validate input format
const phoneNumbers = ['+1-555-0100', '555-0100', 'not-a-phone']
R.filter(phoneNumbers, matches(/^\+?\d{1,3}-\d{3}-\d{4}$/))
// => ['+1-555-0100']

See also includes.

matchesShape

Creates a predicate that tests if an object has the property values in a pattern.

Similar to where, but compares values with strict equality (===) instead of running predicates. Properties not in the pattern are ignored.

Signature
function matchesShape<T extends object>(pattern: Partial<T>): Predicate<T>
Example
import * as R from 'remeda'
import { matchesShape } from '@ontologyio/receta/predicate'

const events = [
  { type: 'click', x: 100, y: 200 },
  { type: 'keypress', key: 'Enter' },
  { type: 'click', x: 150, y: 250 }
]

// Find click events
R.filter(events, matchesShape({ type: 'click' }))
// => click events

// Real-world: Pattern matching on API responses
const responses = [
  { status: 'success', data: { id: 1 } },
  { status: 'error', message: 'Not found' },
  { status: 'success', data: { id: 2 } }
]
R.filter(responses, matchesShape({ status: 'success' }))
// => success responses

See also where, eq.

neq

Creates a predicate that tests if a value does not equal another value.

Uses strict inequality (!==).

Signature
function neq<T>(expected: T): Predicate<T>
Example
import * as R from 'remeda'

const numbers = [1, 2, 3, 2, 1]
R.filter(numbers, neq(2)) // => [1, 3, 1]

See also eq.

never

Creates a predicate that always returns false.

Useful as a default or fallback predicate for filtering out all items.

Signature
function never<T>(): Predicate<T>
Example
import * as R from 'remeda'
import { never } from '@ontologyio/receta/predicate'

// Filter out all items
R.filter([1, 2, 3], never()) // => []

// Real-world: Disable filtering temporarily
const isDebugMode = process.env.DEBUG === 'true'
const predicate = isDebugMode ? never<Log>() : (log) => log.level === 'error'

See also always.

not

Negates a predicate.

Returns a predicate that returns the opposite boolean value.

Signature
function not<T>(predicate: Predicate<T>): Predicate<T>
Example
import * as R from 'remeda'
import { eq, not, isEmpty } from '@ontologyio/receta/predicate'

const numbers = [1, 2, 3, 2, 1]
R.filter(numbers, not(eq(2))) // => [1, 3, 1]

// Real-world: Filter non-empty strings
const names = ['Alice', '', 'Bob', '', 'Charlie']
R.filter(names, not(isEmpty)) // => ['Alice', 'Bob', 'Charlie']

// Complex negation
const users = [
  { name: 'Alice', admin: true },
  { name: 'Bob', admin: false },
  { name: 'Charlie', admin: false }
]
R.filter(users, not((u) => u.admin)) // => non-admin users

See also and, or.

oneOf

Creates a predicate that tests if a value is in a list.

Uses strict equality (===) for comparison.

Signature
function oneOf<T>(values: readonly T[]): Predicate<T>
Example
import * as R from 'remeda'
import { oneOf } from '@ontologyio/receta/predicate'

const numbers = [1, 2, 3, 4, 5]
R.filter(numbers, oneOf([1, 3, 5])) // => [1, 3, 5]

// Real-world: Filter by allowed statuses
const orders = [
  { id: 1, status: 'pending' },
  { id: 2, status: 'shipped' },
  { id: 3, status: 'cancelled' },
  { id: 4, status: 'delivered' }
]
R.filter(
  orders,
  (o) => oneOf(['pending', 'shipped'])(o.status)
) // => pending and shipped orders

// More concise with prop
import { prop } from '@ontologyio/receta/predicate'
R.filter(orders, prop('status', oneOf(['pending', 'shipped'])))

See also eq, or.

or

Combines multiple predicates with logical OR.

Returns a predicate that is true if any predicate returns true. Short-circuits on the first true result.

Overload 1
function or<T, A extends T, B extends T>(first: TypePredicate<T, A>, second: TypePredicate<T, B>): TypePredicate<T, A | B>
Overload 2
function or<T, A extends T, B extends T, C extends T>(first: TypePredicate<T, A>, second: TypePredicate<T, B>, third: TypePredicate<T, C>): TypePredicate<T, A | B | C>
Overload 3
function or<T>(...predicates: Predicate<T>[]): Predicate<T>
Example
import * as R from 'remeda'
import { eq, or } from '@ontologyio/receta/predicate'

// Match multiple values
const numbers = [1, 2, 3, 4, 5]
R.filter(numbers, or(eq(1), eq(3), eq(5))) // => [1, 3, 5]

// Real-world: Filter by multiple statuses
const orders = [
  { id: 1, status: 'pending' },
  { id: 2, status: 'shipped' },
  { id: 3, status: 'delivered' },
  { id: 4, status: 'cancelled' }
]
R.filter(
  orders,
  (o) => or(
    eq('pending'),
    eq('shipped')
  )(o.status)
) // => pending and shipped orders

See also and, not, oneOf.

prop

Creates a predicate that tests a specific property of an object.

Signature
function prop<T, K extends keyof T>(key: K, predicate: Predicate<T[K]>): Predicate<T>
Example
import * as R from 'remeda'
import { prop, gt, oneOf } from '@ontologyio/receta/predicate'

const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 17 },
  { name: 'Charlie', age: 30 }
]

// Test single property
R.filter(users, prop('age', gt(18))) // => Alice and Charlie

// Combine with other predicates
R.filter(users, prop('name', oneOf(['Alice', 'Bob'])))
// => Alice and Bob

// Real-world: Nested property access
const orders = [
  { id: 1, user: { country: 'US' } },
  { id: 2, user: { country: 'UK' } },
  { id: 3, user: { country: 'US' } }
]
// Use by() for nested access
R.filter(orders, by((o) => o.user.country, eq('US')))
// => US orders

See also where, oneOf.

satisfies

Creates a predicate that tests if a value satisfies a custom condition.

This is just an identity function that makes code more readable.

Signature
function satisfies<T>(predicate: Predicate<T>): Predicate<T>
Example
import * as R from 'remeda'
import { satisfies } from '@ontologyio/receta/predicate'

const numbers = [1, 2, 3, 4, 5]
R.filter(numbers, satisfies((n) => n % 2 === 0)) // => [2, 4]

// Makes complex predicates more readable
const users = [
  { name: 'Alice', age: 25, premium: true },
  { name: 'Bob', age: 17, premium: false },
  { name: 'Charlie', age: 30, premium: true }
]
R.filter(
  users,
  satisfies((u) => u.age >= 18 && u.premium)
)

See also where.

startsWith

Creates a predicate that tests if a string starts with a prefix.

Case-sensitive.

Signature
function startsWith(prefix: string): Predicate<string>
Example
import * as R from 'remeda'

const names = ['Alice', 'Bob', 'Alex', 'Barbara']
R.filter(names, startsWith('A')) // => ['Alice', 'Alex']

// Real-world: Filter files by extension
const files = ['app.ts', 'test.spec.ts', 'config.json']
R.filter(files, (f) => !startsWith('test.')(f)) // => non-test files

See also endsWith, includes.

where

Creates a predicate that tests object properties against a schema.

Each key in the schema maps to a predicate that tests the corresponding property. All predicates must pass for the overall predicate to return true.

Signature
function where<T extends object>(schema: PredicateSchema<T>): Predicate<T>
Example
import * as R from 'remeda'
import { where, gt, lt, eq } from '@ontologyio/receta/predicate'

interface User {
  age: number
  name: string
  active: boolean
}

const users: User[] = [
  { age: 25, name: 'Alice', active: true },
  { age: 17, name: 'Bob', active: true },
  { age: 30, name: 'Charlie', active: false }
]

// Filter with multiple conditions
R.filter(users, where({
  age: gt(18),
  active: Boolean  // shorthand for (v) => Boolean(v)
}))
// => [{ age: 25, name: 'Alice', active: true }]

// Real-world: Database-like queries
const products = [
  { price: 10, category: 'electronics', inStock: true },
  { price: 50, category: 'electronics', inStock: false },
  { price: 15, category: 'books', inStock: true }
]
R.filter(products, where({
  category: eq('electronics'),
  inStock: Boolean,
  price: lt(30)
}))
// => [{ price: 10, category: 'electronics', inStock: true }]

See also oneOf, prop.

xor

Combines multiple predicates with logical XOR (exclusive or).

Returns a predicate that is true if exactly one predicate returns true.

Signature
function xor<T>(...predicates: Predicate<T>[]): Predicate<T>
Example
import * as R from 'remeda'
import { gt, lt, xor } from '@ontologyio/receta/predicate'

const numbers = [1, 5, 10, 15, 20]
// Keep numbers that are either < 8 OR > 12, but not both
R.filter(numbers, xor(lt(8), gt(12))) // => [1, 5, 15, 20]
// 10 is excluded because it's neither < 8 nor > 12

// Real-world: Exclusive features (must have one but not both)
const products = [
  { id: 1, premium: true, trial: false },  // valid
  { id: 2, premium: false, trial: true },  // valid
  { id: 3, premium: true, trial: true },   // invalid (both)
  { id: 4, premium: false, trial: false }  // invalid (neither)
]
R.filter(
  products,
  xor((p) => p.premium, (p) => p.trial)
) // => products 1 and 2

See also or, and.

Types

Predicate

A function that takes a value and returns a boolean.

Predicates are used for filtering, validation, and type narrowing. They can be composed using combinators like and, or, and not.

Signature
type Predicate<T> = (value: T) => boolean
Example
// Simple predicate
const isPositive: Predicate<number> = (n) => n > 0

// Type-narrowing predicate
const isString: Predicate<unknown> = (value): value is string =>
  typeof value === 'string'

PredicateSchema

A schema definition for the where function.

Maps object keys to predicates that test the corresponding values.

Signature
type PredicateSchema<T> = {
  [K in keyof T]?: Predicate<T[K]>
}
Example
interface User {
  age: number
  name: string
  active: boolean
}

const schema: PredicateSchema<User> = {
  age: (n) => n >= 18,
  name: (s) => s.length > 0,
  active: Boolean
}

TypePredicate

A function that takes a value and returns a type predicate.

Type predicates enable TypeScript to narrow types in control flow.

Signature
type TypePredicate<T, U extends T> = (value: T) => value is U
Example
const isString: TypePredicate<unknown, string> = (value): value is string =>
  typeof value === 'string'

const value: unknown = 'hello'
if (isString(value)) {
  // TypeScript knows value is string here
  console.log(value.toUpperCase())
}

On this page