memo
Problem
A pure sync function is called repeatedly with the same arguments and the computation is expensive — you need to cache results and avoid redundant work.
Solution
Use memo(fn, options?) to memoize with an optional maxSize (LRU cap) and a custom key function. Returns a Memoized<T> with .clear(), .invalidate(), and .size.
ts
import { memo } from '@vielzeug/arsenal';
// or: import { memo } from '@vielzeug/arsenal/cache';
const expensiveCalc = memo(
(n: number) => {
// simulate expensive work
return n * n;
},
{ maxSize: 100 },
);
expensiveCalc(4); // computed: 16
expensiveCalc(4); // cached: 16
expensiveCalc.size; // 1
expensiveCalc.invalidate(4); // removes entry for 4
expensiveCalc.clear(); // clears all entriesCustom key for object arguments
ts
import { memo } from '@vielzeug/arsenal';
const formatLabel = memo((params: { page: number; size: number }) => `Page ${params.page} of ${params.size}`, {
key: ({ page, size }) => `${page}:${size}`,
});
formatLabel({ page: 1, size: 20 }); // 'Page 1 of 20' — computed
formatLabel({ page: 1, size: 20 }); // cachedAsync caching — use stash instead
memo only accepts sync functions. For async caching with TTL and stampede prevention use stash.getOrSet:
ts
import { stash } from '@vielzeug/arsenal';
const userCache = stash<User>({ ttlMs: 60_000, maxSize: 100 });
// Concurrent callers with the same key share one in-flight Promise
const user = await userCache.getOrSet('user:1', () => fetchUser(1));Pitfalls
memoonly accepts sync functions — passing an async function is a compile-time error.- Pass a
keyfunction when arguments are objects — without it, arguments areJSON.stringify-ed, which may be unstable for non-plain objects. - There is no TTL option. Use
stashwhen time-based expiry is required.