Skip to content

Repository files navigation

Polyfp

Publish Status Test Status

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.

🔑 Key Features

  • 🎯 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.

📦 Installation

# npm
npm install polyfp

🚀 Usage Paradigms

Choose the workflow that best fits your project architecture:

  1. 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 }
  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();
  3. 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();

⚙️ TypeScript Global Augmentation

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 Structure

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})`);

About

A functional programming polyfill for typescript.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages