npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

undumbed

v1.1.0

Published

Array, Object, Set, Map and other structure as they should just be

Readme

🚀 Undumbed

Array, Object, Set, Map and other structures as they should just be

npm version License: MIT

Undumbed extends JavaScript's native objects with powerful functional programming methods, making your code more expressive and concise. No more importing utility libraries for common operations!

✨ Features

  • 🔢 Enhanced Arrays: chunk, distinct, zip, flatten, partition, collect, sliding windows, scan operations
  • 📦 Powerful Objects: map, filter, reduce, merge, pick, omit, deep operations
  • 🛡️ Advanced Type Guards: comprehensive type checking including primitives, iterables, generators
  • 🎯 Try Monad: elegant error handling with pattern matching and side effects
  • 🔄 Function Utilities: compose, pipe, curry, memoize, partial application with type-level computing
  • 📝 Zero Dependencies: lightweight and performant
  • 🏷️ Full TypeScript Support: complete type definitions with advanced type-level computing

📦 Installation

npm install undumbed

🚀 Quick Start

import 'undumbed';

// Enhanced Arrays with functional operations
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Basic operations
numbers.chunk(3);              // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
numbers.distinct();            // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers.sum();                // 55
numbers.median();             // 5.5

// Advanced functional operations
const [evens, odds] = numbers.partition(x => x % 2 === 0);  // [[2, 4, 6, 8, 10], [1, 3, 5, 7, 9]]
numbers.sliding(3);           // [[1, 2, 3], [2, 3, 4], [3, 4, 5], ...]
numbers.scanLeft((a, b) => a + b, 0);  // [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
numbers.collect(x => x % 2 === 0 ? x * 2 : undefined);  // [4, 8, 12, 16, 20]

// Powerful Objects with advanced operations
const user = { name: "Alice", age: 25, city: "NYC" };
const settings = { theme: "dark", age: 30, lang: "en" };

user.map((k, v) => typeof v === 'string' ? v.toUpperCase() : v);  // { name: "ALICE", age: 25, city: "NYC" }
user.merge(settings);         // { name: "Alice", age: 30, city: "NYC", theme: "dark", lang: "en" }
user.pick(['name', 'age']);   // { name: "Alice", age: 25 }
user.mapKeys(k => k.toUpperCase());  // { NAME: "Alice", AGE: 25, CITY: "NYC" }

// Advanced Type Guards
import { Type } from 'undumbed';
Type.isString("hello");       // true
Type.isPrimitive(42);         // true
Type.isIterable([1, 2, 3]);   // true
Type.isPromise(fetch('/api')); // true

// Try Monad with advanced error handling
import { Try } from 'undumbed';
const parseNumber = Try(() => parseInt("42"));

parseNumber.isSuccess();      // true
parseNumber.fold(e => "error", v => `value: ${v}`);  // "value: 42"
parseNumber.filter(n => n > 0).tap(n => console.log(n)).getOrElse(0);  // 42

// Function utilities with type-level computing
const pipeline = Function.pipe(
  (x: number) => x + 1,
  (x: number) => x * 2,
  (x: number) => x.toString(),
  (s: string) => s + "!"
);
pipeline(5);                  // "12!" - types validated at compile time

const curriedAdd = Function.curry((a: number, b: number, c: number) => a + b + c);
curriedAdd(1)(2)(3);          // 6 - perfect type inference

📚 API Reference

🔢 Array Extensions

Undumbed provides a comprehensive set of array operations, from basic utilities to advanced functional programming methods.

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Basic operations
arr.chunk(3);                    // [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
arr.groupBy(x => x % 3);         // Group by remainder
arr.sum();                       // 55
arr.median();                    // 5.5
arr.last();                      // 10

// Functional operations
arr.zipWithIndex();              // [[1, 0], [2, 1], [3, 2], ...]
arr.distinct();                  // Remove duplicates
arr.flatten();                   // Flatten nested arrays

// Advanced functional operations
const [evens, odds] = arr.partition(x => x % 2 === 0);
// evens: [2, 4, 6, 8, 10], odds: [1, 3, 5, 7, 9]

const doubled = arr.collect(x => x % 2 === 0 ? x * 2 : undefined);
// [4, 8, 12, 16, 20] - map + filter in one pass

// Sliding window operations
arr.sliding(3);                  // [[1,2,3], [2,3,4], [3,4,5], ..., [8,9,10]]
arr.sliding(3, 2);               // [[1,2,3], [3,4,5], [5,6,7], [7,8,9]]

// Scan operations: accumulator at each step
arr.scanLeft((acc, x) => acc + x, 0);
// [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55] - running sums

arr.scanRight((x, acc) => x + acc, 0);
// [55, 54, 52, 49, 45, 40, 34, 27, 19, 10, 0] - running sums from right

// Lazy evaluation with generators
const lazy = arr.lazy();
lazy.map(x => x * 2)
    .filter(x => x > 10)
    .take(3)
    .toArray();                  // [12, 14, 16] - computed on demand

// Utilities
arr.pick();                      // Random element
arr.shuffle();                   // Shuffle array
arr.take(3);                     // [1, 2, 3]
arr.takeRight(2);               // [9, 10]

📦 Object Extensions

Comprehensive object manipulation with functional programming patterns and advanced merging capabilities.

const obj = { name: "John", age: 30, city: "NYC" };

// Functional operations
obj.map((k, v) => typeof v === 'string' ? v.toUpperCase() : v);
obj.filter((k, v) => typeof v === 'string');
obj.reduce((acc, k, v) => acc + (typeof v === 'number' ? v : 0), 0);

// Object merging and manipulation
const obj1 = { a: 1, b: 2, shared: "first" };
const obj2 = { c: 3, d: 4, shared: "second" };

obj1.merge(obj2);                // { a: 1, b: 2, shared: "second", c: 3, d: 4 }
obj1.mergeWith(obj2, (key, val1, val2) => 
  key === 'shared' ? `${val1}+${val2}` : val2
);                               // Custom merge logic

// Deep merging for nested objects
const deep1 = { user: { name: "John", settings: { theme: "dark" } } };
const deep2 = { user: { age: 30, settings: { lang: "en" } } };
deep1.deepMerge(deep2);          // Recursively merges nested objects

// Property selection and manipulation
obj.pick(['name', 'age']);       // { name: "John", age: 30 }
obj.omit(['city']);              // { name: "John", age: 30 }
obj.keys();                      // ["name", "age", "city"] - explicit helper
obj.invert();                    // { "John": "name", "30": "age", "NYC": "city" }

// Key/value transformation
obj.mapKeys(k => k.toUpperCase());     // { NAME: "John", AGE: 30, CITY: "NYC" }

// Utilities
obj.isEmpty();                   // false
obj.show();                      // "{ name: John, age: 30, city: NYC }"
obj.excludes(['age']);           // { name: "John", city: "NYC" }
obj.updateAt('age', 31);         // { name: "John", age: 31, city: "NYC" }

⚠️ Note technique: Object.prototype.values est désactivé en raison d'un conflit avec V8. Voir limitations techniques pour plus de détails.

🛡️ Type Guards

Comprehensive type checking utilities including advanced type detection.

import { Type } from 'undumbed';

// Basic type guards
Type.isString(value);            // Check if string
Type.isNumber(value);            // Check if number  
Type.isArray(value);             // Check if array
Type.isObject(value);            // Check if object
Type.isFunction(value);          // Check if function
Type.isDate(value);              // Check if Date
Type.isError(value);             // Check if Error
Type.isNil(value);               // Check if null or undefined
Type.isNotNil(value);            // Check if not null/undefined

// Advanced type guards
Type.isPrimitive(value);         // string | number | boolean | null | undefined | bigint | symbol
Type.isPromise(value);           // Promise or thenable object
Type.isIterable(value);          // Has Symbol.iterator (arrays, strings, Sets, Maps, etc.)
Type.isGenerator(value);         // Generator object with next/return/throw
Type.isFrozen(value);            // Object.isFrozen check
Type.isSealed(value);            // Object.isSealed check

🎯 Try Monad

Elegant error handling with pattern matching, state checking, and side effects.

import { Try } from 'undumbed';

// Basic Try operations
const parseJson = (str: string) => Try(() => JSON.parse(str));

const result = parseJson('{"name": "John"}')
  .map(obj => obj.name)
  .map(name => name.toUpperCase())
  .getOrElse("Unknown");         // "JOHN"

const failed = parseJson('invalid json')
  .map(obj => obj.name)
  .getOrElse("Unknown");         // "Unknown"

// Advanced error handling
const parseNumber = (str: string) => Try(() => parseInt(str));

// State checking
const result = parseNumber("42");
result.isSuccess();              // true
result.isFailure();              // false

// Pattern matching with fold
const message = result.fold(
  (error) => `Failed: ${error.message}`,
  (value) => `Success: ${value}`
);                               // "Success: 42"

// Filtering with predicates
const evenNumber = parseNumber("42")
  .filter(n => n % 2 === 0);     // Success: 42

const oddNumber = parseNumber("41")
  .filter(n => n % 2 === 0);     // Failure: "Filter failed"

// Side effects without breaking the chain
parseNumber("42")
  .tap(value => console.log(`Parsed: ${value}`))    // Logs: "Parsed: 42"
  .map(n => n * 2)
  .tapError(err => console.log(`Error: ${err}`))    // Not executed
  .getOrElse(0);                 // 84

// Chain operations with error recovery
Try(() => riskyOperation())
  .flatMap(result => Try(() => anotherRiskyOperation(result)))
  .recover(error => handleError(error))
  .getOrElse(defaultValue);

🔄 Function Utilities

Advanced functional programming utilities with type-level computing and generic implementations.

// Basic function utilities
Function.identity(x);            // Returns x unchanged
Function.doNothing();            // No-op function
Function.compose(f, g);          // Function composition: g(f(x))
Function.negate(predicate);      // Negate boolean function
Function.promisify(fn);          // Convert callback to Promise

// Advanced functional utilities
const getConfig = Function.constant({ theme: "dark", lang: "en" });
getConfig();                     // Always returns the same object

// Left-to-right composition with compile-time type validation
const addOne = (x: number) => x + 1;
const double = (x: number) => x * 2;
const toString = (x: number) => x.toString();
const addExclamation = (s: string) => s + "!";

const pipeline = Function.pipe(addOne, double, toString, addExclamation);
pipeline(5);                     // "12!" (5 -> 6 -> 12 -> "12" -> "12!")

// Complex pipelines with mixed types - validated at compile time
const parseNumber = (s: string) => parseInt(s);
const square = (n: number) => n * n;
const isEven = (n: number) => n % 2 === 0;
const boolToString = (b: boolean) => b ? "even" : "odd";

const complexPipe = Function.pipe(parseNumber, square, isEven, boolToString);
complexPipe("3");                // "odd" (3 -> 9 -> false -> "odd")

// Memoization for expensive computations
const fibonacci = Function.memoize((n: number): number => 
  n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
);
fibonacci(40);                   // Fast on subsequent calls

// Execute only once
const initializeApp = Function.once(() => {
  console.log("App initialized!");
  return "initialized";
});
initializeApp();                 // Logs and returns "initialized"
initializeApp();                 // Returns cached result, no log

// Generic currying with automatic arity detection
const add = (a: number, b: number) => a + b;
const curriedAdd = Function.curry(add);
const add5 = curriedAdd(5);
add5(10);                        // 15

// Works with any number of arguments and mixed types
const processData = (greeting: string, count: number, active: boolean, tags: string[]) => 
  ({ greeting, count, active, tags, length: greeting.length + count });

const curriedProcess = Function.curry(processData);
const withGreeting = curriedProcess("Hello");
const withCount = withGreeting(42);
const result = withCount(true)(["tag1", "tag2"]);  // Perfect type inference

// Uncurrying - convert curried functions back to normal functions
const curriedMultiply = (a: number) => (b: number) => a * b;
const multiply = Function.uncurry(curriedMultiply);
multiply(6, 7);                  // 42

// Perfect round-trip with curry
const add4 = (a: number, b: number, c: number, d: number) => a + b + c + d;
const curriedAdd4 = Function.curry(add4);
const backToNormal = Function.uncurry(curriedAdd4);
backToNormal(1, 2, 3, 4);        // 10 - same as original function

🎨 Any Utilities

import { Any } from 'undumbed';

Any.isEmpty(value);              // Check if value is empty
Any.isNotEmpty(value);           // Check if value is not empty
Any.areEquals(a, b);             // Deep equality check

🔧 Advanced Usage

Array Static Methods

Array.range(5);                  // [0, 1, 2, 3, 4]
Array.range(5, i => i * 2);      // [0, 2, 4, 6, 8]
Array.zip([1, 2], ['a', 'b']);   // [[1, 'a'], [2, 'b']]
Array.cartesianProduct([1, 2], ['a', 'b']); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]

// Seamless integration with functional methods
Array.range(10).partition(x => x % 3 === 0);     // [[0, 3, 6, 9], [1, 2, 4, 5, 7, 8]]
Array.range(5).scanLeft((a, b) => a + b, 0);     // [0, 0, 1, 3, 6, 10]

Object Static Methods

Object.sequence({ 
  a: Promise.resolve(1), 
  b: Promise.resolve(2) 
});                              // Promise<{ a: 1, b: 2 }>

🎯 Why Undumbed?

  • Familiar API: Extends native objects you already know
  • Functional Programming: Immutable operations with chainable methods
  • Type Safety: Full TypeScript support with advanced type-level computing
  • Performance: Optimized implementations with minimal overhead
  • Comprehensive: Everything you need for modern JavaScript/TypeScript development
  • Zero Dependencies: No external dependencies to worry about

📄 License

MIT © Methrat0n

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📞 Support


Made with ❤️ by the Spyrals team