Collection
31 exports from @ontologyio/receta/collection.
Everything exported from @ontologyio/receta/collection. New here? Start with the Collection guide.
Functions
batchBy
Groups consecutive items in an array based on a predicate or grouping function.
Unlike groupBy which groups ALL matching items together, batchBy only groups
consecutive items that produce the same grouping key. Useful for identifying runs,
sequences, or consecutive states in time-series data.
function batchBy<T, K extends string | number>(items: readonly T[], fn: (item: T) => K): readonly (readonly T[])[]function batchBy<T, K extends string | number>(fn: (item: T) => K): (items: readonly T[]) => readonly (readonly T[])[]// Data-first: Group consecutive same values
batchBy([1, 1, 2, 2, 2, 3, 1, 1], x => x)
// => [[1, 1], [2, 2, 2], [3], [1, 1]]
// Group consecutive dates by day
const events = [
{ timestamp: '2024-01-01T10:00:00Z', event: 'login' },
{ timestamp: '2024-01-01T11:00:00Z', event: 'click' },
{ timestamp: '2024-01-02T09:00:00Z', event: 'login' },
{ timestamp: '2024-01-02T10:00:00Z', event: 'logout' },
]
batchBy(events, e => e.timestamp.split('T')[0])
// => [
// [{ timestamp: '2024-01-01T10:00:00Z', ... }, { timestamp: '2024-01-01T11:00:00Z', ... }],
// [{ timestamp: '2024-01-02T09:00:00Z', ... }, { timestamp: '2024-01-02T10:00:00Z', ... }]
// ]
// Group consecutive status changes
const tasks = [
{ id: 1, status: 'pending' },
{ id: 2, status: 'pending' },
{ id: 3, status: 'done' },
{ id: 4, status: 'done' },
{ id: 5, status: 'pending' },
]
batchBy(tasks, t => t.status)
// => [
// [{ id: 1, status: 'pending' }, { id: 2, status: 'pending' }],
// [{ id: 3, status: 'done' }, { id: 4, status: 'done' }],
// [{ id: 5, status: 'pending' }]
// ]
// Data-last (in pipe)
pipe(
[1, 1, 2, 2, 2, 3, 1, 1],
batchBy(x => x)
)
// => [[1, 1], [2, 2, 2], [3], [1, 1]]See also groupBy, chunk.
cartesianProduct
Generates the Cartesian product of multiple arrays.
Creates all possible combinations by taking one element from each input array. Useful for generating test matrices, A/B test variants, configuration combinations, or any scenario requiring all possible combinations.
Type-safe for 2-5 arrays with specific tuple types, falls back to generic array for more than 5 arrays.
function cartesianProduct<A, B>(arr1: readonly A[], arr2: readonly B[]): readonly [A, B][]function cartesianProduct<A, B, C>(arr1: readonly A[], arr2: readonly B[], arr3: readonly C[]): readonly [A, B, C][]function cartesianProduct<A, B, C, D>(arr1: readonly A[], arr2: readonly B[], arr3: readonly C[], arr4: readonly D[]): readonly [A, B, C, D][]function cartesianProduct<A, B, C, D, E>(arr1: readonly A[], arr2: readonly B[], arr3: readonly C[], arr4: readonly D[], arr5: readonly E[]): readonly [A, B, C, D, E][]function cartesianProduct<T>(...arrays: readonly (readonly T[])[]): readonly T[][]// Two arrays
cartesianProduct(['a', 'b'], [1, 2, 3])
// => [['a', 1], ['a', 2], ['a', 3], ['b', 1], ['b', 2], ['b', 3]]
// Three arrays (A/B test variants)
const sizes = ['S', 'M', 'L']
const colors = ['red', 'blue']
const materials = ['cotton', 'polyester']
cartesianProduct(sizes, colors, materials)
// => [
// ['S', 'red', 'cotton'],
// ['S', 'red', 'polyester'],
// ['S', 'blue', 'cotton'],
// ['S', 'blue', 'polyester'],
// ['M', 'red', 'cotton'],
// ...
// ]
// Test matrix generation
const browsers = ['chrome', 'firefox', 'safari']
const platforms = ['mac', 'windows', 'linux']
const versions = ['v1', 'v2']
cartesianProduct(browsers, platforms, versions)
// => [
// ['chrome', 'mac', 'v1'],
// ['chrome', 'mac', 'v2'],
// ['chrome', 'windows', 'v1'],
// ...
// ]
// Configuration combinations
pipe(
cartesianProduct(['dev', 'prod'], ['us', 'eu'], ['v1', 'v2']),
R.map(([env, region, version]) => ({
env,
region,
version,
url: `https://${env}-${region}.example.com/${version}`
}))
)See also zip.
diff
Compares two collections and returns added, updated, removed, and unchanged items.
Useful for syncing data, detecting changes, and implementing optimistic updates.
function diff<T, TId extends string | number>(oldItems: readonly T[], newItems: readonly T[], getId: (item: T) => TId, isEqual?: Comparator<T> | undefined): DiffResult<T>function diff<T, TId extends string | number>(newItems: readonly T[], getId: (item: T) => TId, isEqual?: Comparator<T> | undefined): (oldItems: readonly T[]) => DiffResult<T>// Data-first
const oldUsers = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
const newUsers = [
{ id: 1, name: 'Alicia' }, // updated
{ id: 3, name: 'Charlie' } // added
]
diff(oldUsers, newUsers, (u) => u.id)
// => {
// added: [{ id: 3, name: 'Charlie' }],
// updated: [{ old: { id: 1, name: 'Alice' }, new: { id: 1, name: 'Alicia' } }],
// removed: [{ id: 2, name: 'Bob' }],
// unchanged: []
// }
// Data-last (in pipe)
pipe(
oldUsers,
diff(newUsers, (u) => u.id)
)See also union, intersect.
flatten
Flattens a tree structure into a flat array with optional depth control and path tracking.
Unlike Remeda's flat() which flattens nested arrays, this function handles tree structures
where each node contains children. Useful for hierarchical data like file systems, org charts,
or nested comments.
function flatten<T>(items: readonly T[], config: FlattenConfig<T> & { includePath: true; }): readonly FlattenedItem<T>[]function flatten<T>(items: readonly T[], config: FlattenConfig<T> & { includePath?: false | undefined; }): readonly T[]function flatten<T>(items: readonly T[], config: FlattenConfig<T>): readonly T[] | readonly FlattenedItem<T>[]function flatten<T>(config: FlattenConfig<T> & { includePath: true; }): (items: readonly T[]) => readonly FlattenedItem<T>[]function flatten<T>(config: FlattenConfig<T> & { includePath?: false | undefined; }): (items: readonly T[]) => readonly T[]function flatten<T>(config: FlattenConfig<T>): (items: readonly T[]) => readonly T[] | readonly FlattenedItem<T>[]// Data-first: File system tree
interface FileNode {
name: string
children?: FileNode[]
}
const tree: FileNode[] = [
{
name: 'src',
children: [
{ name: 'index.ts' },
{ name: 'utils', children: [{ name: 'helper.ts' }] }
]
}
]
flatten(tree, { getChildren: (n) => n.children })
// => [
// { name: 'src', children: [...] },
// { name: 'index.ts' },
// { name: 'utils', children: [...] },
// { name: 'helper.ts' }
// ]
// With path tracking
flatten(tree, {
getChildren: (n) => n.children,
includePath: true
})
// => [
// { item: { name: 'src', ... }, path: [], depth: 0 },
// { item: { name: 'index.ts' }, path: [{ name: 'src', ... }], depth: 1 },
// { item: { name: 'utils', ... }, path: [{ name: 'src', ... }], depth: 1 },
// { item: { name: 'helper.ts' }, path: [{ name: 'src', ... }, { name: 'utils', ... }], depth: 2 }
// ]
// With max depth
flatten(tree, {
getChildren: (n) => n.children,
maxDepth: 1
})
// => [
// { name: 'src', children: [...] },
// { name: 'index.ts' },
// { name: 'utils', children: [...] }
// ]
// (stops at depth 1, doesn't include helper.ts)
// Data-last (in pipe)
pipe(
tree,
flatten({ getChildren: (n) => n.children })
)See also nest.
groupByPath
Groups items by a nested object path.
Useful for grouping objects by nested properties like user.role or metadata.category.
Uses type-safe path access via Option pattern. Items with undefined/null paths are grouped under the 'undefined' key.
function groupByPath<T>(items: readonly T[], path: string): Record<string, T[]>function groupByPath<T>(path: string): (items: readonly T[]) => Record<string, T[]>// Data-first
const users = [
{ name: 'Alice', profile: { role: 'admin' } },
{ name: 'Bob', profile: { role: 'user' } },
{ name: 'Charlie', profile: { role: 'admin' } }
]
groupByPath(users, 'profile.role')
// => {
// admin: [
// { name: 'Alice', profile: { role: 'admin' } },
// { name: 'Charlie', profile: { role: 'admin' } }
// ],
// user: [{ name: 'Bob', profile: { role: 'user' } }]
// }
// Data-last (in pipe)
pipe(
users,
groupByPath('profile.role')
)See also nest.
indexByUnique
Creates an index (map) from an array, ensuring keys are unique.
Returns a Result to handle duplicate key errors safely. Useful for normalizing data and creating lookup tables.
function indexByUnique<T, TKey extends string | number>(items: readonly T[], getKey: (item: T) => TKey, config?: IndexConfig | undefined): Result<Record<TKey, T>, DuplicateKeyError>function indexByUnique<T, TKey extends string | number>(getKey: (item: T) => TKey, config?: IndexConfig | undefined): (items: readonly T[]) => Result<Record<TKey, T>, DuplicateKeyError>Fails with DuplicateKeyError.
// Data-first
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
indexByUnique(users, (u) => u.id)
// => Ok({ 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } })
// Duplicate keys
const duplicates = [
{ id: 1, name: 'Alice' },
{ id: 1, name: 'Alicia' }
]
indexByUnique(duplicates, (u) => u.id)
// => Err(DuplicateKeyError: Duplicate key found: 1)
// Handle collisions with config
indexByUnique(duplicates, (u) => u.id, { onCollision: 'last' })
// => Ok({ 1: { id: 1, name: 'Alicia' } }) // keeps last
indexByUnique(duplicates, (u) => u.id, { onCollision: 'first' })
// => Ok({ 1: { id: 1, name: 'Alice' } }) // keeps first
// Data-last (in pipe)
pipe(
users,
indexByUnique((u) => u.id)
)See also nest.
insertAt
Inserts one or more elements at a specific index (immutably).
Creates a new array with elements inserted at the specified index, shifting
existing elements as needed. More ergonomic than splice for insertion-only operations.
Built on top of Remeda's splice for consistency.
function insertAt<T>(items: readonly T[], index: number, values: T | readonly T[]): readonly T[]function insertAt<T>(index: number, values: T | readonly T[]): (items: readonly T[]) => readonly T[]// Data-first: Insert single element
insertAt(['a', 'b', 'd', 'e'], 2, 'c')
// => ['a', 'b', 'c', 'd', 'e']
// Insert multiple elements
insertAt([1, 2, 5, 6], 2, [3, 4])
// => [1, 2, 3, 4, 5, 6]
// Insert at beginning
insertAt(['b', 'c'], 0, 'a')
// => ['a', 'b', 'c']
// Insert at end
insertAt(['a', 'b'], 2, 'c')
// => ['a', 'b', 'c']
// Negative index (from end)
insertAt(['a', 'b', 'd'], -1, 'c')
// => ['a', 'b', 'c', 'd']
// Add item to todo list at specific position
interface Todo {
id: number
text: string
}
const todos: Todo[] = [
{ id: 1, text: 'Buy milk' },
{ id: 3, text: 'Walk dog' },
]
insertAt(todos, 1, { id: 2, text: 'Read book' })
// => [
// { id: 1, text: 'Buy milk' },
// { id: 2, text: 'Read book' },
// { id: 3, text: 'Walk dog' },
// ]
// Data-last (in pipe)
pipe(
['a', 'b', 'd', 'e'],
insertAt(2, 'c')
)
// => ['a', 'b', 'c', 'd', 'e']See also updateAt, removeAtIndex, moveIndex.
intersect
Finds elements that exist in both collections using a custom comparator.
Similar to Set intersection but works with objects and custom equality.
function intersect<T>(items1: readonly T[], items2: readonly T[], isEqual?: Comparator<T> | undefined): T[]function intersect<T>(items2: readonly T[], isEqual?: Comparator<T> | undefined): (items1: readonly T[]) => T[]// Data-first - with primitive values
intersect([1, 2, 3], [2, 3, 4])
// => [2, 3]
// With objects and custom comparator
const assigned = [{ taskId: 1 }, { taskId: 2 }]
const completed = [{ taskId: 2 }, { taskId: 3 }]
intersect(assigned, completed, (a, b) => a.taskId === b.taskId)
// => [{ taskId: 2 }] // tasks that are both assigned and completed
// Data-last (in pipe)
pipe(
assigned,
intersect(completed, (a, b) => a.taskId === b.taskId)
)See also union, diff.
moveIndex
Moves an element from one index to another (immutably).
Creates a new array with the element at fromIndex moved to toIndex,
shifting other elements as needed. Useful for drag-and-drop reordering,
priority adjustments, or any scenario requiring index-based repositioning.
function moveIndex<T>(items: readonly T[], fromIndex: number, toIndex: number): readonly T[]function moveIndex(fromIndex: number, toIndex: number): <T>(items: readonly T[]) => readonly T[]// Data-first: Move element forward
moveIndex(['a', 'b', 'c', 'd', 'e'], 1, 3)
// => ['a', 'c', 'd', 'b', 'e']
// Move element backward
moveIndex(['a', 'b', 'c', 'd', 'e'], 3, 1)
// => ['a', 'd', 'b', 'c', 'e']
// Drag-and-drop reordering
interface Task {
id: number
title: string
priority: number
}
const tasks: Task[] = [
{ id: 1, title: 'Task 1', priority: 1 },
{ id: 2, title: 'Task 2', priority: 2 },
{ id: 3, title: 'Task 3', priority: 3 },
]
// Move task from position 0 to position 2
moveIndex(tasks, 0, 2)
// => [
// { id: 2, title: 'Task 2', priority: 2 },
// { id: 3, title: 'Task 3', priority: 3 },
// { id: 1, title: 'Task 1', priority: 1 },
// ]
// No-op if indices are same
moveIndex([1, 2, 3], 1, 1)
// => [1, 2, 3]
// Negative indices (from end)
moveIndex(['a', 'b', 'c', 'd'], -1, 0)
// => ['d', 'a', 'b', 'c']
// Data-last (in pipe)
pipe(
['a', 'b', 'c', 'd', 'e'],
moveIndex(1, 3)
)
// => ['a', 'c', 'd', 'b', 'e']See also insertAt, removeAtIndex, updateAt.
nest
Groups items hierarchically by multiple keys, creating a nested structure.
Useful for organizing data like comments grouped by user and post, or products grouped by category and subcategory.
function nest<T>(items: readonly T[], keys: readonly (keyof T | ((item: T) => string | number))[]): NestedMap<T>function nest<T>(keys: readonly (keyof T | ((item: T) => string | number))[]): (items: readonly T[]) => NestedMap<T>// Data-first
const comments = [
{ userId: 1, postId: 10, text: 'Hello' },
{ userId: 1, postId: 10, text: 'World' },
{ userId: 2, postId: 20, text: 'Foo' }
]
nest(comments, ['userId', 'postId'])
// => {
// 1: {
// 10: [{ userId: 1, postId: 10, text: 'Hello' }, { userId: 1, postId: 10, text: 'World' }]
// },
// 2: {
// 20: [{ userId: 2, postId: 20, text: 'Foo' }]
// }
// }
// Data-last (in pipe)
pipe(
comments,
nest(['userId', 'postId'])
)See also groupByPath.
paginate
Paginates an array using offset-based pagination.
Useful for implementing API pagination, infinite scroll, and data tables.
function paginate<T>(items: readonly T[], config: PaginationConfig): PaginatedResult<T>function paginate<T>(config: PaginationConfig): (items: readonly T[]) => PaginatedResult<T>// Data-first
const users = Array.from({ length: 100 }, (_, i) => ({ id: i }))
paginate(users, { page: 1, pageSize: 20 })
// => {
// items: [first 20 users],
// page: 1,
// pageSize: 20,
// total: 100,
// hasNext: true,
// hasPrevious: false
// }
// Data-last (in pipe)
pipe(
users,
paginate({ page: 2, pageSize: 20 })
)See also paginateCursor.
paginateCursor
Paginates an array using cursor-based pagination.
More efficient than offset pagination for large datasets and real-time data. Prevents issues with missing/duplicate items during pagination.
function paginateCursor<T, TCursor>(items: readonly T[], getCursor: (item: T) => TCursor, config: CursorPaginationConfig<TCursor>): CursorPaginatedResult<T, TCursor>function paginateCursor<T, TCursor>(getCursor: (item: T) => TCursor, config: CursorPaginationConfig<TCursor>): (items: readonly T[]) => CursorPaginatedResult<T, TCursor>// Data-first
const messages = Array.from({ length: 25 }, (_, i) => ({ id: `msg_${i + 1}` }))
paginateCursor(messages, (m) => m.id, { limit: 10 })
// => {
// items: [first 10 messages],
// nextCursor: 'msg_10',
// hasMore: true
// }
// Continue from cursor
paginateCursor(messages, (m) => m.id, { cursor: 'msg_10', limit: 10 })
// Data-last (in pipe)
pipe(
messages,
paginateCursor((m) => m.id, { limit: 10 })
)See also paginate.
removeAtIndex
Removes an element at a specific index (immutably).
Creates a new array with the element at the specified index removed. More ergonomic
than splice for single-element removal. Built on top of Remeda's splice for consistency.
function removeAtIndex<T>(items: readonly T[], index: number): readonly T[]function removeAtIndex(index: number): <T>(items: readonly T[]) => readonly T[]// Data-first: Remove element
removeAtIndex(['a', 'b', 'c', 'd'], 2)
// => ['a', 'b', 'd']
// Remove at beginning
removeAtIndex([1, 2, 3], 0)
// => [2, 3]
// Remove at end
removeAtIndex([1, 2, 3], 2)
// => [1, 2]
// Negative index (from end)
removeAtIndex(['a', 'b', 'c', 'd'], -1)
// => ['a', 'b', 'c']
// Out of bounds returns original array
removeAtIndex([1, 2, 3], 10)
// => [1, 2, 3]
// Remove todo item
interface Todo {
id: number
text: string
}
const todos: Todo[] = [
{ id: 1, text: 'Buy milk' },
{ id: 2, text: 'Read book' },
{ id: 3, text: 'Walk dog' },
]
removeAtIndex(todos, 1)
// => [
// { id: 1, text: 'Buy milk' },
// { id: 3, text: 'Walk dog' },
// ]
// Data-last (in pipe)
pipe(
['a', 'b', 'c', 'd'],
removeAtIndex(2)
)
// => ['a', 'b', 'd']
// Chain multiple removals
pipe(
[1, 2, 3, 4, 5],
removeAtIndex(0), // [2, 3, 4, 5]
removeAtIndex(-1) // [2, 3, 4]
)
// => [2, 3, 4]See also insertAt, updateAt, moveIndex.
symmetricDiff
Finds elements that exist in either collection but not both (symmetric difference).
Similar to XOR operation on sets.
function symmetricDiff<T>(items1: readonly T[], items2: readonly T[], isEqual?: Comparator<T> | undefined): T[]function symmetricDiff<T>(items2: readonly T[], isEqual?: Comparator<T> | undefined): (items1: readonly T[]) => T[]// Data-first - with primitive values
symmetricDiff([1, 2, 3], [2, 3, 4])
// => [1, 4] // 1 only in first, 4 only in second
// With objects
const planned = [{ id: 1 }, { id: 2 }]
const actual = [{ id: 2 }, { id: 3 }]
symmetricDiff(planned, actual, (a, b) => a.id === b.id)
// => [{ id: 1 }, { id: 3 }] // id 1 not executed, id 3 not planned
// Data-last (in pipe)
pipe(
planned,
symmetricDiff(actual, (a, b) => a.id === b.id)
)See also diff, union.
union
Merges two collections, removing duplicates using a custom comparator.
Similar to Set union operation but works with objects and custom equality.
function union<T>(items1: readonly T[], items2: readonly T[], isEqual?: Comparator<T> | undefined): T[]function union<T>(items2: readonly T[], isEqual?: Comparator<T> | undefined): (items1: readonly T[]) => T[]// Data-first - with primitive values
union([1, 2, 3], [3, 4, 5])
// => [1, 2, 3, 4, 5]
// With objects and custom comparator
const users1 = [{ id: 1, name: 'Alice' }]
const users2 = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
union(users1, users2, (a, b) => a.id === b.id)
// => [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
// Data-last (in pipe)
pipe(
users1,
union(users2, (a, b) => a.id === b.id)
)See also intersect, symmetricDiff.
updateAt
Updates (replaces) an element at a specific index (immutably).
Creates a new array with the element at the specified index replaced with a new value.
More ergonomic than splice for single-element replacement. Built on top of Remeda's
splice for consistency.
function updateAt<T>(items: readonly T[], index: number, value: T): readonly T[]function updateAt<T>(index: number, value: T): (items: readonly T[]) => readonly T[]// Data-first: Update element
updateAt(['a', 'b', 'c', 'd'], 2, 'X')
// => ['a', 'b', 'X', 'd']
// Update at beginning
updateAt([1, 2, 3], 0, 10)
// => [10, 2, 3]
// Update at end
updateAt([1, 2, 3], 2, 30)
// => [1, 2, 30]
// Negative index (from end)
updateAt(['a', 'b', 'c', 'd'], -1, 'Z')
// => ['a', 'b', 'c', 'Z']
// Out of bounds returns original array
updateAt([1, 2, 3], 10, 99)
// => [1, 2, 3]
// Update todo item
interface Todo {
id: number
text: string
done: boolean
}
const todos: Todo[] = [
{ id: 1, text: 'Buy milk', done: false },
{ id: 2, text: 'Read book', done: false },
{ id: 3, text: 'Walk dog', done: false },
]
updateAt(todos, 1, { id: 2, text: 'Read book', done: true })
// => [
// { id: 1, text: 'Buy milk', done: false },
// { id: 2, text: 'Read book', done: true },
// { id: 3, text: 'Walk dog', done: false },
// ]
// Data-last (in pipe)
pipe(
['a', 'b', 'c', 'd'],
updateAt(2, 'X')
)
// => ['a', 'b', 'X', 'd']See also insertAt, removeAtIndex, moveIndex.
windowSliding
Creates a sliding window over an array with configurable size and step.
A sliding window creates overlapping sub-arrays by moving a fixed-size window across the array. Useful for moving averages, n-gram analysis, pattern detection, and time-series analysis.
function windowSliding<T>(items: readonly T[], config: WindowSlidingConfig): readonly (readonly T[])[]function windowSliding<T>(config: WindowSlidingConfig): (items: readonly T[]) => readonly (readonly T[])[]// Data-first: Simple sliding window (step=1)
windowSliding([1, 2, 3, 4, 5], { size: 3 })
// => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// Sliding window with step
windowSliding([1, 2, 3, 4, 5, 6], { size: 3, step: 2 })
// => [[1, 2, 3], [3, 4, 5]]
// Moving average calculation
const prices = [100, 102, 101, 105, 103, 107]
pipe(
prices,
windowSliding({ size: 3 }),
R.map(window => window.reduce((a, b) => a + b, 0) / window.length)
)
// => [101, 102.66666666666667, 103, 105]
// N-gram analysis
const words = ['the', 'quick', 'brown', 'fox', 'jumps']
windowSliding(words, { size: 2 })
// => [['the', 'quick'], ['quick', 'brown'], ['brown', 'fox'], ['fox', 'jumps']]
// Pattern detection (3-item sequences)
const sequence = [1, 2, 3, 2, 3, 4, 3, 4, 5]
pipe(
sequence,
windowSliding({ size: 3 }),
R.filter(window => window[0]! < window[1]! && window[1]! < window[2]!)
)
// => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// Data-last (in pipe)
pipe(
[1, 2, 3, 4, 5],
windowSliding({ size: 3 })
)
// => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]See also chunk, batchBy.
Values
DuplicateKeyError
Error thrown when a duplicate key is found during indexing.
const DuplicateKeyError: typeof DuplicateKeyErrorTypes
Comparator
Comparator function for custom equality checks.
type Comparator<T> = (a: T, b: T) => booleanCursorPaginatedResult
Result of a cursor-based pagination operation.
interface CursorPaginatedResult<T, TCursor> {
readonly items: readonly T[]
readonly nextCursor?: TCursor | undefined
readonly hasMore: boolean
}const page: CursorPaginatedResult<User, string> = {
items: users,
nextCursor: 'user_456',
hasMore: true
}CursorPaginationConfig
Cursor-based pagination configuration.
interface CursorPaginationConfig<TCursor> {
readonly cursor?: TCursor
readonly limit: number
}const config: CursorPaginationConfig<string> = {
cursor: 'user_123',
limit: 20
}DiffResult
Result of a diff operation showing added, updated, and removed items.
interface DiffResult<T> {
readonly added: readonly T[]
readonly updated: readonly UpdatedItem<T>[]
readonly removed: readonly T[]
readonly unchanged: readonly T[]
}const result: DiffResult<User> = {
added: [newUser],
updated: [{ old: oldUser, new: updatedUser }],
removed: [deletedUser],
unchanged: [sameUser]
}FlattenConfig
Configuration for flatten operation.
interface FlattenConfig<T> {
readonly getChildren: (node: T) => readonly T[] | undefined
readonly maxDepth?: number
readonly includePath?: boolean
}const config: FlattenConfig<FileNode> = {
getChildren: (node) => node.children,
maxDepth: 3,
includePath: true
}FlattenedItem
Result item from flatten operation with path information.
interface FlattenedItem<T> {
readonly item: T
readonly path: readonly T[]
readonly depth: number
}IndexConfig
Configuration for index operations with collision handling.
interface IndexConfig {
readonly onCollision?: 'error' | 'first' | 'last'
}const config: IndexConfig = {
onCollision: 'error' // or 'first' | 'last'
}NestConfig
Configuration for nested grouping operations.
interface NestConfig<T> {
readonly by: readonly (keyof T | ((item: T) => string | number))[]
readonly createEmpty?: () => unknown
}const config: NestConfig<Comment> = {
by: ['userId', 'postId'],
createEmpty: () => []
}NestedMap
A nested map structure for hierarchical grouping.
type NestedMap<T> = {
[key: string | number]: T | NestedMap<T> | readonly T[]
}const nested: NestedMap<Comment> = {
'user_1': {
'post_1': [comment1, comment2],
'post_2': [comment3]
}
}PaginatedResult
Result of a pagination operation.
interface PaginatedResult<T> {
readonly items: readonly T[]
readonly page: number
readonly pageSize: number
readonly total: number
readonly hasNext: boolean
readonly hasPrevious: boolean
}const page: PaginatedResult<User> = {
items: users,
page: 1,
pageSize: 20,
total: 100,
hasNext: true,
hasPrevious: false
}PaginationConfig
Configuration for pagination operations.
interface PaginationConfig {
readonly page: number
readonly pageSize: number
}const config: PaginationConfig = {
page: 1,
pageSize: 20
}UpdatedItem
Represents an item that was updated in a diff operation.
interface UpdatedItem<T> {
readonly old: T
readonly new: T
}WindowSlidingConfig
Configuration for sliding window operation.
interface WindowSlidingConfig {
readonly size: number
readonly step?: number
}const config: WindowSlidingConfig = {
size: 3,
step: 1
}