@certes/list
v0.1.1
Published
A set of baseline functions in JavaScript.
Readme
@certes/list
Curried array operations for functional programming in TypeScript.
[!CAUTION]
⚠️ Active Development & Alpha Status
This repository is currently undergoing active development.
Until
1.0.0release:
- Stability: APIs are subject to breaking changes without prior notice.
- Releases: Current releases (tags/npm packages) are strictly for testing and integration feedback.
- Production: Do not use this software in production environments where data integrity or high availability is required.
Installation
npm install @certes/listFeatures
- Pure Functions: All operations are side-effect free and non-mutating
- Curried by Default: Optimized for composition and partial application
- Performance-First: Manual loop implementations optimized for V8
- Type-Safe: Full TypeScript support with strict typing
- Zero Dependencies: Minimal footprint
Usage
import { filter, map, reduce } from '@certes/list';
// Basic usage
const nums = [1, 2, 3, 4, 5];
const doubled = map((x: number) => x * 2)(nums);
// [2, 4, 6, 8, 10]
// Currying enables partial application
const filterEven = filter((x: number) => !(x & 1));
const evens = filterEven(nums);
// [2, 4]
// Composition
const sum = reduce((acc: number, x: number) => acc + x)(0);
const sumOfEvens = (arr: number[]) => sum(filterEven(arr));
sumOfEvens(nums);
// 6API Reference
Transformation
map<T, R>(fn: (x: T, idx?: number) => R) => (arr: T[]) => R[]
Maps over an array, applying the function to each element.
const square = (x: number) => x * x;
map(square)([1, 2, 3]);
// [1, 4, 9]filter<T>(predicate: (x: T, idx?: number) => boolean) => (arr: T[]) => T[]
Returns elements that satisfy the predicate.
const isPositive = (x: number) => x > 0;
filter(isPositive)([-1, 0, 1, 2]);
// [1, 2]flatMap<T, R>(fn: (x: T, idx?: number) => R[]) => (arr: T[]) => R[]
Maps each element to an array and flattens the result.
const duplicate = (x: number) => [x, x];
flatMap(duplicate)([1, 2, 3]);
// [1, 1, 2, 2, 3, 3]flatten<T>(arr: T[][]) => T[]
Flattens a nested array by one level.
flatten([[1, 2], [3, 4], [5]]);
// [1, 2, 3, 4, 5]reverse<T>(arr: T[]) => T[]
Reverses array order.
reverse([1, 2, 3, 4]);
// [4, 3, 2, 1]Reduction
reduce<T, R>(fn: (acc: R, x: T) => R) => (init: R) => (arr: T[]) => R
Left-to-right reduction with accumulator.
const multiply = (acc: number, x: number) => acc * x;
reduce(multiply)(1)([2, 3, 4]);
// 24reduceRight<T, R>(fn: (acc: R, x: T) => R) => (init: R) => (arr: T[]) => R
Right-to-left reduction with accumulator.
const concat = (acc: string, x: string) => `${acc}${x}`;
reduceRight(concat)('')(['a', 'b', 'c']);
// 'cba'Searching
find<T>(predicate: (x: T, idx?: number) => boolean) => (arr: T[]) => T | null
Returns first element matching predicate, or null.
find((x: number) => x > 3)([1, 2, 3, 4, 5]);
// 4findIndex<T>(predicate: (x: T, idx?: number) => boolean) => (arr: T[]) => number
Returns index of first match, or -1.
findIndex((x: number) => x > 3)([1, 2, 3, 4, 5]);
// 3findLast<T>(predicate: (x: T, idx?: number) => boolean) => (arr: T[]) => T | null
Returns last element matching predicate, or null.
findLast((x: number) => !(x & 1))([1, 2, 3, 4, 5]);
// 4findLastIndex<T>(predicate: (x: T, idx?: number) => boolean) => (arr: T[]) => number
Returns index of last match, or -1.
findLastIndex((x: number) => !(x & 1))([1, 2, 3, 4, 5]);
// 3includes<T>(x: T) => (arr: T[]) => boolean
Determines if array contains element (strict equality).
includes(3)([1, 2, 3, 4, 5]);
// trueindexOf<T>(x: T) => (arr: T[]) => number
Returns first index of element, or -1.
indexOf(3)([1, 2, 3, 4, 5]);
// 2Testing
every<T>(comparator: (x: T) => boolean) => (arr: T[]) => boolean
Tests if all elements satisfy comparator.
every((x: number) => x > 0)([1, 2, 3]);
// truesome<T>(comparator: (x: T) => boolean) => (arr: T[]) => boolean
Tests if any element satisfies comparator.
some((x: number) => x > 3)([1, 2, 3, 4, 5]);
// trueConstruction
concat<T>(first: T[]) => (second: T[]) => T[]
Concatenates two arrays.
concat([1, 2])([3, 4]);
// [1, 2, 3, 4]push<T>(arr: T[]) => (x: T) => T[]
Returns new array with element appended.
push([1, 2, 3])(4);
// [1, 2, 3, 4]unshift<T>(arr: T[]) => (x: T) => T[]
Returns new array with element prepended.
unshift([2, 3, 4])(1);
// [1, 2, 3, 4]slice(start: number) => (end: number) => <T>(arr: T[]) => T[]
Returns slice from start (inclusive) to end (exclusive).
slice(1)(3)([0, 1, 2, 3, 4]);
// [1, 2]shift<T>(arr: T[]) => [T | null, T[]]
Returns tuple of first element (head) and remaining elements (tail).
shift([1, 2, 3, 4]);
// [1, [2, 3, 4]]
shift([]);
// [null, []]Design Principles
Currying
Functions are curried to enable partial application and composition:
import { filter, map, reduce, every } from '@certes/list';
// Create reusable predicates
const isPositive = (x: number) => x > 0;
const filterPositive = filter(isPositive);
// Compose operations
const sumPositive = (arr: number[]) =>
reduce((a: number, b: number) => a + b)(0)(filterPositive(arr));
// Pipeline-style composition
const processNumbers = (arr: number[]) => {
const positives = filterPositive(arr);
const doubled = map((x: number) => x * 2)(positives);
return every((x: number) => x < 100)(doubled);
};Purity
No function mutates its input or produces side effects:
const original = [1, 2, 3];
const reversed = reverse(original);
console.log(original); // [1, 2, 3] - unchanged
console.log(reversed); // [3, 2, 1]Type Utilities
export type ArrayElementType<T> = T extends (infer E)[] ? E : T;
export type Comparator<T> = (x: T) => boolean;
export type Predicate<T> = (x: T, idx?: number) => boolean;
export type Accumulator<T, R> = (acc: R, x: T) => R;
export type MapFn<T, R> = (x: T, idx?: number) => R;License
MIT
Contributing
Part of the @certes monorepo. See main repository for contribution guidelines.
