Implement a memoize helper that caches the return value of a function based on the full argument list it was called with — any count, any types. A single-argument memoizer is a one-liner (new Map().get(arg)); the variadic version is where the interesting choices live. On a cache hit, the original function must not run a second time.
// Returns a wrapped function that caches return values by the
// exact sequence of arguments it was called with.
function memoize<F extends (...args: any[]) => any>(fn: F): F;
let calls = 0;
const add = memoize((a, b) => {
calls++;
return a + b;
});
add(1, 2); // 3
add(1, 2); // 3 (cache hit — calls still 1)
add(2, 1); // 3 (different arg order — calls now 2)
// Distinct arities are distinct cache entries.
const sum = memoize((...nums) => nums.reduce((a, n) => a + n, 0));
sum(1, 2); // 3, runs
sum(1, 2, 3); // 6, runs (different argument count)
sum(1, 2); // 3, cache hit
sum(); // 0, runs (zero-arg call has its own slot)
// Object args are cached by REFERENCE, not by shape.
const ident = memoize((obj) => ({ ...obj }));
const a = { id: 1 };
ident(a); // runs
ident(a); // cache hit (same reference)
ident({ id: 1 }); // runs (different object, same shape)
(1, 2) and (1, 2, 3) must be distinct cache entries.Map treats keys.0 and '0' are different keys. null and undefined are different keys. NaN matches NaN (Map-style key equality).undefined returns too. A function whose result is undefined should still be a cache hit on the second call — don't probe with cache.get(...) === undefined to decide whether to recompute.memoize produces a fresh cache. Two memoized wrappers of the same function don't share entries.JSON.stringify. Two different references with the same JSON shape would collide, cyclic objects would throw, and functions/undefined would silently disappear from the key. Use a structure that respects reference identity.this-binding and side effects are out of scope. Assume fn is pure and called as a plain function.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.