@catbee/utils
Version:
A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.
369 lines (366 loc) • 14.9 kB
TypeScript
/*
* The MIT License
*
* Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* Splits an array into chunks of the specified size.
*
* @template T The type of array elements.
* @param {T[]} array - The array to split into chunks.
* @param {number} size - The number of elements per chunk.
* @returns {T[][]} A new array containing chunked arrays.
* @throws {TypeError} If array is not an array.
* @throws {Error} If chunk size is not a positive integer.
*/
declare function chunk<T>(array: readonly T[], size: number): T[][];
/**
* Removes duplicate values from an array.
* Optionally enforces uniqueness by a key function.
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @param {(item: T) => unknown} [keyFn] - Optional function to determine uniqueness by key.
* @returns {T[]} A new array with unique values.
*/
declare function unique<T>(array: readonly T[], keyFn?: (item: T) => unknown): T[];
/**
* Deeply flattens a nested array to a single-level array (iterative, stack-based).
*
* @template T The leaf type of array elements.
* @param {readonly unknown[]} array - The (possibly deeply nested) input array.
* @returns {T[]} A deeply flattened array.
*/
declare function flattenDeep<T>(array: readonly unknown[]): T[];
/**
* Returns a random element from an array, or undefined if empty. Uses crypto-secure randomness
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @returns {T | undefined} A randomly selected item, or undefined if array is empty or not an array.
*
* @example
* ```ts
* securePick(['a','b','c']); // -> 'b'
* ```
*/
declare function random<T>(array: readonly T[]): T | undefined;
type StrNumSym = string | number | symbol;
/**
* Groups items in an array by a nested key or key function.
*
* @template T The type of array elements.
* @overload
* @param {T[]} array - The array to group.
* @param {keyof T} key - Property key to group by.
* @returns {Record<string, readonly T[]>}
* @overload
* @param {T[]} array - The array to group.
* @param {(item: T) => StrNumSym} keyFn - Function to generate group key from item.
* @returns {Record<K, readonly T[]>}
* @param {T[]} array - The array to group.
* @param {keyof T | ((item: T) => StrNumSym)} keyOrFn - Nested property key or key selector.
* @returns {Record<StrNumSym, readonly T[]>} Grouped result object.
*/
declare function groupBy<T>(array: T[], key: keyof T): Record<string, readonly T[]>;
declare function groupBy<T, K extends StrNumSym>(array: T[], keyFn: (item: T) => K): Record<K, readonly T[]>;
/**
* Shuffles an array using the Fisher-Yates algorithm. Uses crypto-secure randomness.
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @returns {T[]} A new shuffled array.
* @throws {TypeError} If array is not an array.
*/
declare function shuffle<T>(array: readonly T[]): T[];
/**
* Returns an array of property values from an array of objects. Returns undefined for missing properties.
*
* @template T The type of array elements.
* @template K The object property to pluck.
* @param {T[]} array - The input array.
* @param {K} key - The property name to pluck.
* @returns {T[K][]} Array of property values.
*/
declare function pluck<T, K extends keyof T>(array: readonly T[], key: K): T[K][];
/**
* Returns values in array A that are not in array B.
*
* @template T The type of array elements.
* @param {T[]} a - First array.
* @param {T[]} b - Second array.
* @returns {T[]} Elements in A that are not in B.
*/
declare function difference<T>(a: readonly T[], b: readonly T[]): T[];
/**
* Returns common values between arrays A and B.
*
* @template T The type of array elements.
* @param {T[]} a - First array.
* @param {T[]} b - Second array.
* @returns {T[]} Elements that exist in both arrays.
*/
declare function intersect<T>(a: readonly T[], b: readonly T[]): T[];
/**
* Sorts an array of objects by a nested key using Merge Sort (O(n log n)).
* Missing/undefined keys are sorted to the "end" (asc) or "start" (desc").
* Optionally accepts a custom compare function or collator.
*
* @template T The type of array elements (objects).
* @param {T[]} array - Array of objects to sort.
* @param {string | ((item: T) => any)} key - Dot-notated key (e.g., "profile.age") or function.
* @param {"asc" | "desc"} [direction="asc"] - Sort direction: 'asc' or 'desc'.
* @param {(a: T, b: T) => number} [compareFn] - Optional custom compare function.
* @returns {T[]} A new sorted array.
* @throws {TypeError} If array is not an array.
*/
declare function mergeSort<T>(array: readonly T[], key: string | ((item: T) => unknown), direction?: 'asc' | 'desc', compareFn?: (a: T, b: T) => number): T[];
/**
* Combines multiple arrays into a single array of grouped elements.
* Output length equals the length of the shortest input array.
*
* This implementation ensures type safety and avoids holes in output.
*
* @example
* ```ts
* zip([1, 2], ['a', 'b']) => [[1, 'a'], [2, 'b']]
* ```
* @param {...Array<T>[]} arrays - Two or more arrays to zip together.
* @returns {Array<T[]>} Array of grouped elements.
*/
declare function zip<T>(...arrays: ReadonlyArray<T>[]): T[][];
/**
* Splits an array into two arrays based on a predicate function.
* Supports type-guard narrowing via overload.
*
* @template T The type of array elements.
* @overload
* @param {readonly T[]} array - The input array.
* @param {(item: T, index: number, array: readonly T[]) => item is U} predicate - Type guard predicate.
* @returns {[U[], Exclude<T, U>[]]} A tuple of two arrays: [matched, unmatched].
* @overload
* @param {readonly T[]} array - The input array.
* @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Boolean predicate.
* @returns {[T[], T[]]} A tuple of two arrays: [matched, unmatched].
*/
declare function partition<T, U extends T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => item is U): [U[], Exclude<T, U>[]];
declare function partition<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): [T[], T[]];
/**
* Generates an array of numbers within a specified range.
*
* @param {number} start - Start of range (inclusive).
* @param {number} end - End of range (exclusive).
* @param {number} [step=1] - Step between numbers.
* @returns {number[]} Array of numbers in range.
*/
declare function range(start: number, end: number, step?: number): number[];
/**
* Returns the first `n` elements from an array.
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @param {number} [n=1] - Number of elements to take.
* @returns {T[]} New array with first n elements.
*/
declare function take<T>(array: readonly T[], n?: number): T[];
/**
* Takes elements from an array while predicate returns true.
*
* @template T The type of array elements.
* @param {readonly T[]} array - Input array.
* @param {(item: T, index: number) => boolean} predicate - Condition function.
* @returns {T[]} New array with taken elements.
*
* @example
* ```ts
* takeWhile([1,2,3,4], (n) => n < 3); // -> [1,2]
* ```
*/
declare function takeWhile<T>(array: readonly T[], predicate: (item: T, index: number) => boolean): T[];
/**
* Removes all falsy values from an array.
* `false`, `null`, `0`, `""`, `undefined`, and `NaN` are falsy.
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @returns {NonNullable<T>[]} New array with falsy values removed.
*/
declare function compact<T>(array: readonly T[]): NonNullable<T>[];
/**
* Counts array elements by a key function.
*
* @template T The type of array elements.
* @param {T[]} array - The input array.
* @param {(item: T) => StrNumSym} keyFn - Function to generate count key.
* @returns {Record<string, number>} Object with counts by key.
*/
declare function countBy<T>(array: readonly T[], keyFn: (item: T) => StrNumSym): Record<string, number>;
/**
* Toggles an item in array (adds if not present, removes if present).
*
* @template T
* @param {readonly T[]} array
* @param {T} item
* @returns {T[]} New array with item toggled.
*
* @example
* ```ts
* toggle([1,2,3], 2); // -> [1,3]
* toggle([1,3], 2); // -> [1,3,2]
* ```
*/
declare function toggle<T>(array: readonly T[], item: T): T[];
/**
* Returns a cryptographically secure random index for an array.
* Used internally for secure pick/shuffle operations.
*
* @param {number} max Upper bound (exclusive).
* @returns {number} A secure random integer in range `[0, max)`.
* @throws {RangeError} If `max` is not a positive number.
*
* @example
* ```ts
* secureIndex(10); // -> 3 (unpredictable)
* ```
*/
declare function secureIndex(max: number): number;
/**
* Returns a secure random element from an array using Node crypto.
*
* @template T
* @param {readonly T[]} array
* @returns {T | undefined}
*/
declare const secureRandom: <T>(array: readonly T[]) => T | undefined;
/**
* Returns the last element in the array that satisfies the provided testing function.
*
* @template T
* @param {readonly T[]} array - The input array.
* @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to test each element.
* @returns {T | undefined} The found element, or undefined if not found.
*/
declare function findLast<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): T | undefined;
/**
* Returns the index of the last element in the array that satisfies the provided testing function.
*
* @template T
* @param {readonly T[]} array - The input array.
* @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to test each element.
* @returns {number} The index, or -1 if not found.
*/
declare function findLastIndex<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): number;
/**
* Splits an array into chunks based on a predicate function.
* Each chunk starts when predicate returns true.
*
* @template T
* @param {readonly T[]} array - The input array.
* @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to determine chunk boundaries.
* @returns {T[][]} Array of chunked arrays.
*/
declare function chunkBy<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): T[][];
/**
* Removes all occurrences of a value from an array.
*
* @template T
* @param {readonly T[]} array - The input array.
* @param {T} value - Value to remove.
* @returns {T[]} New array with value removed.
*/
declare function remove<T>(array: readonly T[], value: T): T[];
/**
* Checks if an array is sorted in ascending or descending order.
*
* @template T
* @param {readonly T[]} array - The input array.
* @param {'asc' | 'desc'} [direction='asc'] - Sort direction.
* @param {(a: T, b: T) => number} [compareFn] - Optional compare function.
* @returns {boolean} True if sorted, false otherwise.
*/
declare function isSorted<T>(array: readonly T[], direction?: 'asc' | 'desc', compareFn?: (a: T, b: T) => number): boolean;
/**
* Returns the first element of an array, or undefined if empty.
*
* @template T
* @param {readonly T[]} array
* @returns {T | undefined}
*/
declare function headOfArr<T>(array: readonly T[]): T | undefined;
/**
* Returns the last element of an array, or undefined if empty.
*
* @template T
* @param {readonly T[]} array
* @returns {T | undefined}
*/
declare function lastOfArr<T>(array: readonly T[]): T | undefined;
/**
* Drops the first n elements from an array.
*
* @template T
* @param {readonly T[]} array - The source array.
* @param {number} n - Number of elements to drop.
* @returns {T[]} Array with first n elements removed.
*
* @example
* drop([1, 2, 3, 4, 5], 2); // [3, 4, 5]
*/
declare function drop<T>(array: readonly T[], n: number): T[];
/**
* Drops elements from the start of an array while predicate returns true.
*
* @template T
* @param {readonly T[]} array - The source array.
* @param {(item: T, index: number) => boolean} predicate - Condition function.
* @returns {T[]} Array with elements dropped.
*
* @example
* dropWhile([1, 2, 3, 4, 1], x => x < 3); // [3, 4, 1]
*/
declare function dropWhile<T>(array: readonly T[], predicate: (item: T, index: number) => boolean): T[];
/**
* Finds the element with the maximum value for a given key or function.
*
* @template T
* @param {readonly T[]} array - The source array.
* @param {keyof T | ((item: T) => number)} keyOrFn - Property key or function.
* @returns {T | undefined} Element with maximum value.
*
* @example
* maxBy([{a: 1}, {a: 5}, {a: 3}], 'a'); // {a: 5}
* maxBy([{a: 1}, {a: 5}, {a: 3}], x => x.a); // {a: 5}
*/
declare function maxBy<T>(array: readonly T[], keyOrFn: keyof T | ((item: T) => number)): T | undefined;
/**
* Finds the element with the minimum value for a given key or function.
*
* @template T
* @param {readonly T[]} array - The source array.
* @param {keyof T | ((item: T) => number)} keyOrFn - Property key or function.
* @returns {T | undefined} Element with minimum value.
*
* @example
* minBy([{a: 1}, {a: 5}, {a: 3}], 'a'); // {a: 1}
* minBy([{a: 1}, {a: 5}, {a: 3}], x => x.a); // {a: 1}
*/
declare function minBy<T>(array: readonly T[], keyOrFn: keyof T | ((item: T) => number)): T | undefined;
export { chunk, chunkBy, compact, countBy, difference, drop, dropWhile, findLast, findLastIndex, flattenDeep, groupBy, headOfArr, intersect, isSorted, lastOfArr, maxBy, mergeSort, minBy, partition, pluck, random, range, remove, secureIndex, secureRandom, shuffle, take, takeWhile, toggle, unique, zip };