Why Arsenal?
Arsenal favors a curated, typed utility surface over an everything-and-the-kitchen-sink API, with zero dependencies and modern tree-shakeable exports.
| Feature | Arsenal | lodash-es | Remeda |
|---|---|---|---|
| Bundle size | 9.0 KB | ~72 kB | ~18 kB |
| TypeScript-first ergonomics | Partial | ||
| Deep utility coverage | Partial | ||
| Async control-flow helpers | Partial | ||
| Typed predicate functions | Partial | ||
| Tree-shakeable modules | |||
| Zero dependencies |
Use Arsenal when you want one compact, typed utility layer that covers array/object/function/async/math use cases. For money handling, use @vielzeug/coins.
Consider narrower alternatives when you only need a small functional subset and prefer ultra-focused APIs.
Installation
sh
pnpm add @vielzeug/arsenalsh
npm install @vielzeug/arsenalsh
yarn add @vielzeug/arsenalQuick Start
ts
import { chunk, deepMerge, diff, fuzzy, hash, parseJSON, pick, queue, retry } from '@vielzeug/arsenal';
const pages = chunk([1, 2, 3, 4, 5], 2);
const user = pick({ id: 1, name: 'Alice', role: 'admin' }, ['id', 'name']);
const q = queue({ concurrency: 2 });
await q.add(() => fetch('/api/a'));
const health = await retry(() => fetch('/api/health').then((r) => r.json()), {
times: 3,
delay: 250,
timeout: 5000,
});
const cfg = parseJSON('{"api":{"host":"localhost","port":3000}}', {
fallback: { api: { host: 'localhost', port: 3000 } },
});
// Fuzzy search — filter mode returns T[], scored mode returns ScoredResult<T>[]
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
];
const hits = fuzzy(users, 'alice'); // User[]
const ranked = fuzzy(users, 'alice', { scored: true }); // ScoredResult<User>[]
// [{ item: { name: 'Alice', ... }, score: 0.91 }, ...]
// Deep merge with optional array concatenation
deepMerge({ a: { x: 1 } }, { a: { y: 2 } }); // { a: { x: 1, y: 2 } }
deepMerge({ tags: ['a'] }, { tags: ['b'] }, { arrayStrategy: 'concat' }); // { tags: ['a','b'] }
// Structured diff
diff({ port: 3000 }, { port: 4000 });
// { added: [], removed: [], changed: { port: { before: 3000, after: 4000 } } }
// Deterministic cache keys from any value
const key = hash({ sort: 'asc', filter: { role: 'admin' } });Features
- Array:
chunk,compact,countBy,difference,filterMap,flatten,groupBy,indexBy,partition,fuzzy,fuzzyFilter,fuzzyScore,take/drop,union/intersection,zip/unzip, and more - Async:
abortError,attempt,parallel,queue,retry,sleep,waitFor - Cache:
memo(sync LRU memoization),stash(TTL cache with stampede prevention) - Object:
pick,omit,mapValues,mapKeys,filterValues,defaults,deepMerge,shallowMerge,diff,diffArrays,invert,prune,getPath,flattenPaths,unflattenPaths,parseJSON,hash(deterministic, handlesDate/Set/Map/bigint) - Function:
pipe,assert,runAll,debounce,throttle,tap,identity,constant,once,memo - Guards:
allOf,anyOf,noneOf,isArray,isBoolean,isDate,isDefined,isEmpty,isEqual,isError,isFunction,isMatch,isNil,isNumber,isPlainObject,isPrimitive,isPromise,isRegex,isString,isAbortError,shallowEqual - Math:
lerp,normalize,mod,gcd/lcm,variance,standardDeviation,backoff, plus numeric helpers - Random:
draw,random,shuffle,uuid