undumbed
v1.1.0
Published
Array, Object, Set, Map and other structure as they should just be
Maintainers
Readme
🚀 Undumbed
Array, Object, Set, Map and other structures as they should just be
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.valuesest 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
