Skip to content

Bunch of iterable functions I keep using and rewriting in projects that I finally decided to just make a lib of

Notifications You must be signed in to change notification settings

laquasicinque/it-al

Repository files navigation

It-al

A TypeScript iterable utility library providing functional programming utilities for working with iterables as well as a class based interface with an easy chainable and typed API.

Installation

npm install it-al

Features

  • 🔄 Lazy Evaluation - Iterator-based operations are efficient and composable
  • 🍛 Currying Support - Most functions support both direct and curried forms
  • đź”— Method Chaining - Fluent API via Iter and PeekableIter classes
  • 🏷️ Type Safe - Full TypeScript support with proper type inference
  • đź§© Functional - Supports composition via pipe and apply

Quick Start

import { Iter, map, filter, take } from 'it-al';

// Functional style
const result = pipe([
  map((x: number) => x * 2),
  filter((x: number) => x > 5),
  take(3)
])([1, 2, 3, 4, 5, 6]);

// Method chaining style
const result2 = Iter.from([1, 2, 3, 4, 5, 6])
  .map(x => x * 2)
  .filter(x => x > 5)
  .take(3)
  .toArray();

API Reference

Transformation Functions

Function Description Signature
map Transform each item in an iterable <T, U>(iter: Iterable<T>, fn: IterFn<T, U>) => IterableIterator<U>
filter Filter items based on a predicate <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
flat Flatten nested iterables by depth <T, D>(iter: Iterable<T>, depth?: D) => IterableIterator<FlatItem<T, D>>
enumerate Return index-value pairs <T>(iter: Iterable<T>) => IterableIterator<[number, T]>
pluck Extract a property from each item <T, K>(iter: Iterable<T>, key: K) => IterableIterator<T[K]>
tap Run side effects without modifying items <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
scan Like reduce but yields intermediate values <T, U>(iter: Iterable<T>, fn, start?: U) => IterableIterator<U>

Slicing & Limiting

Function Description Signature
take Take first n items <T>(iter: Iterable<T>, n: number) => IterableIterator<T>
skip Skip first n items <T>(iter: Iterable<T>, n: number) => IterableIterator<T>
takeWhile Take items while predicate is true <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
skipWhile Skip items while predicate is true <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
until Take items until predicate is true <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
chunk Split into chunks of size n <T>(iter: Iterable<T>, n: number) => IterableIterator<T[]>
windows Create sliding windows of size n <T>(iter: Iterable<T>, n: number) => IterableIterator<T[]>

Aggregation & Reduction

Function Description Signature
reduce Reduce to a single value <T, U>(iter: Iterable<T>, fn, start: U) => U
sum Sum all numbers (iter: Iterable<number>) => number
product Multiply all numbers (iter: Iterable<number>) => number
average Average all numbers (iter: Iterable<number>) => number
count Count items <T>(iter: Iterable<T>) => number
join Join items into string <T>(iter: Iterable<T>, delimiter?: string) => string
groupBy Group items by key <T, U>(iter: Iterable<T>, fn) => Map<U, T[]>

Searching & Testing

Function Description Signature
find Find first matching item <T>(iter: Iterable<T>, fn: IterFn<T>) => T | null
findIndex Find index of first match <T>(iter: Iterable<T>, fn: IterFn<T>) => number
includes Check if value exists <T>(iter: Iterable<T>, value: T) => boolean
some Test if any item matches <T>(iter: Iterable<T>, fn: IterFn<T>) => boolean
every Test if all items match <T>(iter: Iterable<T>, fn: IterFn<T>) => boolean
first Get first item <T>(iter: Iterable<T>) => T
last Get last item <T>(iter: Iterable<T>) => T | undefined
isEmpty Check if empty (iter: Iterable<unknown>) => boolean
search Recursively search object <U>(obj: unknown, fn) => IterableIterator<KeyValuePair<U>>

Uniqueness & Filtering

Function Description Signature
uniqueBy Get unique items by selector <T>(iter: Iterable<T>, fn: IterFn<T>) => IterableIterator<T>
partition Split into passed/failed arrays <T>(iter: Iterable<T>, fn: IterFn<T>) => [T[], T[]]

Combining & Zipping

Function Description Signature
zip Combine multiple iterables <I>(...iters: I, stopOnMin?: boolean) => ZipOutput<I>
unzip Transpose iterable of arrays <T>(iter: Iterable<T>) => UnzipOutput<T>

Generation & Repetition

Function Description Signature
range Generate range of numbers (stop: number, start?: number, step?: number) => IterableIterator<number>
repeat Repeat iterable n times <T>(iter: Iterable<T>, n: number) => IterableIterator<T>
cycle Cycle through iterable infinitely <T>(iter: Iterable<T>) => IterableIterator<T>
gen Create infinite generator <T>(fn: (n: number) => T) => () => IterableIterator<T>

Object/Entry Operations

Function Description Signature
entries Get key-value pairs <T>(input: T) => IterableIterator<Entry<T>>
allEntries Get entries including Symbols <T>(input: T) => IterableIterator<Entry<T>>
fromEntries Create object from entries <K, V>(iter: Iterable<[K, V]>) => Record<K, V>

Utilities

Function Description Signature
pipe Compose functions left-to-right <I, O>(fns: Function[]) => (item: I) => O
apply Apply functions in order <I, O>(input: I, fns: Function[]) => O
peekable Create peekable iterable <T>(iter: Iterable<T>) => Peekable<T>
isIterable Check if value is iterable <T>(x: unknown) => x is Iterable<T>
isNonStringIterable Check iterable (not string) <T>(x: unknown) => x is Iterable<T>
isAsyncIterable Check if async iterable <T>(x: unknown) => x is AsyncIterable<T>

Class-Based API

Iter<T>

Chainable wrapper around iterables providing a fluent API.

Static Methods

Method Description Return Type
Iter#from(iterable) Create an Iter from any iterable Iter<T>
Iter#safeFrom(maybeIterable?) Create an Iter from unknown input, returns empty Iter if not iterable Iter<T>
Iter#fromAsync(iterable) Create an Iter from async iterable or promises Iter<T>
Iter#fromEntries(obj) Create an Iter from object entries Iter<[K, V]>
Iter#safeFromEntries(obj?) Create an Iter from object entries, returns empty Iter if null/undefined Iter<[K, V]>
Iter#fromRange(stop, start?, step?) Create an Iter from a numeric range Iter<number>
Iter#gen(fn) Create infinite Iter using generator function () => Iter<T>
Iter#zip(iterables, stopOnMin?) Zip multiple iterables into tuples Iter<[...]>
Iter#search(obj, fn, skipAfterYield?) Recursively search object for matching values Iter<KeyValuePair<U>>

Chainable Methods

Returns a new Iter<T> instance for continued chaining.

Method Description
Iter#flatMap(fn) Map and flatten in one step
Iter#flat(depth?) Flatten nested iterables
Iter#map(fn) Transform each item
Iter#filter(fn) Filter items by predicate
Iter#filterNullish() Remove null and undefined values
Iter#unique() Remove duplicate values
Iter#enumerate() Add index to each item as [index, value]
Iter#uniqueBy(fn) Remove duplicates by selector function
Iter#tap(fn) Run side effects without modifying items
Iter#scan(fn, start?) Like reduce but yields intermediate values
Iter#pluck(key) Extract property from each item
Iter#take(n) Take first n items
Iter#chunk(n) Split into chunks of size n
Iter#skip(n) Skip first n items
Iter#takeWhile(fn) Take items while predicate is true
Iter#skipWhile(fn) Skip items while predicate is true
Iter#until(fn) Take items until predicate is true
Iter#windows(size) Create sliding windows of size n
Iter#apply(fn) Apply a function to the iterable
Iter#peekable() Convert to PeekableIter
Iter#repeat(times) Repeat the iterable n times
Iter#cycle() Cycle through iterable infinitely

Terminal Methods

Consumes the iterator and returns a final value.

Method Description Return Type
Iter#first() Get the first item T
Iter#last() Get the last item T | undefined
Iter#find(fn) Find first item matching predicate T | null
Iter#findIndex(fn) Find index of first match number
Iter#includes(value) Check if value exists boolean
Iter#count() Count total items number
Iter#isEmpty() Check if iterable is empty boolean
Iter#forEach(fn) Like Array.forEach but for Iter void
Iter#reduce(fn, start) Reduce to single value U
Iter#every(fn) Test if all items match predicate boolean
Iter#some(fn) Test if any item matches predicate boolean
Iter#unzip() Transpose iterable of arrays UnzipOutput<T>
Iter#partition(fn) Split into [passed, failed] arrays [T[], T[]]
Iter#join(delimiter?) Join items into string string
Iter#groupBy(fn) Group items by key Map<K, T[]>
Iter#sum() Sum all numbers number
Iter#product() Multiply all numbers number
Iter#average() Average all numbers number
Iter#min() Find minimum value T
Iter#max() Find maximum value T
Iter#collect(collector?) Collect using custom collector U
Iter#toArray() Collect all items into an array T[]
Iter#toSet() Collect all items into a Set Set<T>
Iter#toMap() Collect entries into a Map Map<K, V>

PeekableIter<T>

Extends Iter<T> with the ability to peek at the next value without consuming it.

const iter = PeekableIter.from([1, 2, 3]);
console.log(iter.peek()); // 1 (doesn't consume)
console.log(iter.first()); // 1 (consumes)

Additional Method

Method Description Return Type
PeekableIter#peek() Look at next value without consuming it T | undefined

Examples

Currying

import { map, filter, pipe } from 'it-al';

// Curried form
const double = map((x: number) => x * 2);
const isPowerOfTwo = filter((x: number) => Math.sqrt(x, 2) % 1 === 0);

const result = pipe([double, isPowerOfTwo])([1, 2, 3, 4]);
// [2, 4, 8]

Method Chaining

import { Iter } from 'it-al';

const result = Iter.from([1, 2, 3, 4, 5])
  .map(x => x * 2)
  .filter(x => x > 5)
  .take(2)
  .toArray();
// [6, 8]

Lazy Evaluation

import { map, take } from 'it-al';

const expensive = map((x: number) => {
  console.log('Processing:', x);
  return x * 2;
});

// Only processes first 3 items
const result = take(expensive([1, 2, 3, 4, 5, 6, 7, 8]), 3);

for (const _ of result) {}
// Logs: Processing: 1, 2, 3

Working with Infinite Iterators

import { Iter } from 'it-al';

// Generate infinite sequence
const randomNumbers = Iter.gen((n) => Math.random());

// Generates 10 random numbers
const first10 = fibonacci().take(10).toArray();

Grouping and Aggregation

import { Iter } from 'it-al';

const data = [
  { category: 'A', value: 10 },
  { category: 'B', value: 20 },
  { category: 'A', value: 30 },
];

const grouped = Iter.from(data).groupBy(item => item.category);
// Map { 'A' => [{...}, {...}], 'B' => [{...}] }

About

Bunch of iterable functions I keep using and rewriting in projects that I finally decided to just make a lib of

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published