A high-performance, fully typed functional utility belt, LINQ-like query engine, and data structure toolkit for TypeScript & JavaScript.
Designed with type safety, tree-shakability, and developer experience at its core. It brings powerful functional programming (FP) patterns, stream aggregation, and relational query building to your codebase—with zero runtime bloat.
- 🎯 100% Type-Safe: Deep TypeScript inference across all projections, transformations, aggregations, and joins.
- ⚡ Dual Consumption Models: Use as standalone pure functions or extend native prototypes via granular polyfills.
- 🌳 Tree-Shakeable Subpath Exports: Import only the specific function or polyfill you need without pulling in unused code.
- 📊 Query & Aggregation Engines: Perform SQL/LINQ-style lazy evaluation, multi-key grouping, relational joins, and customized stream reductions.
- 📦 Data Structure Extensions: Includes specialized data structures exported cleanly under
./data.
# npm
npm install polyfpChoose the workflow that best fits your project architecture:
-
Pure Functional (Standalone)
Ideal for functional pipelines, strict immutability, and optimal bundler tree-shaking.
import { aggregate } from 'polyfp'; const data = [ { category: 'tech', price: 100 }, { category: 'tech', price: 200 }, ]; const result = aggregate(data) .select('total', 0, (sum, item) => sum + item.price) .select('count', 0, (count) => count + 1) .take(); // { total: 300, count: 2 }
-
Granular Polyfill (Fluent Method Chaining)
Extend standard prototypes on a per-method basis without dirtying global space with unused polyfills. The library uses modern subpath exports to give you full control over bundle size and global prototype augmentation.
// Import the polyfill once to augment Array.prototype and global TypeScript types import 'polyfp/polyfill/array/aggregate'; const data = [ { category: 'tech', price: 100 }, { category: 'tech', price: 200 }, ]; // Call directly on the array instance const result = data .aggregate() .select('total', 0, (sum, item) => sum + item.price) .take();
-
Full polyfill
Instead of a granular polyfill, you can import everything.
// Import all the polyfill import 'polyfp/polyfill'; // Or choose only a specific set of polyfill // import 'polyfp/polyfill/array'; const data = [ { category: 'tech', price: 100 }, { category: 'tech', price: 200 }, ]; // Call directly on the array instance const result = data .aggregate() .select('total', 0, (sum, item) => sum + item.price) .take();
When using any polyfill/* import path, TypeScript automatically augments standard global interfaces (e.g., Array<T>, ReadonlyArray<T>) to provide full autocompletion and type checking for added prototype methods.
// types.ts auto-loads upon importing the polyfill file
import 'polyfp/polyfill/array/aggregate';
const numbers = [1, 2, 3, 4, 5];
// Intellisense automatically recognizes .aggregate()
numbers
.aggregate()
.select('product', 1, (prod, val) => prod * val)
.take();Data structures can't be polyfilled, they are given as is for the developers. You can find adt, stack, queue, deque to name a few that you can use for your project.
You can only import it like any normal packages:
import { Vector } 'polyfp';
// Or specify data directly
// import { Vector } 'polyfp/data';
const point = new Vector(2, 3);
console.log(`Coordinate: (${point.x}, ${point.y})`);