memoize Without A Resolver On A Multi-Parameter Function

ID

javascript.memoize_multiple_params

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

JavaScript

Tags

caching, reliability, suspicious-comparison

Description

Reports a utility-library memoize applied to a function of more than one parameter with no resolver argument:

const area = _.memoize((width, height) => width * height);

area(2, 3);   // 6
area(2, 9);   // 6 again — the cache was keyed on 2 alone

Rationale

The default resolver of memoize is the first argument. Every call that agrees on it therefore gets the first result back, whatever the remaining arguments say.

Nothing about the code shows it. The memoized function keeps its signature and its type, every call site keeps compiling, and the wrong value comes back silently. It is also unusually hard to catch by hand, because the first call for any pair of arguments is always correct — the bug only appears on the second, and only when the first argument repeats.

Remediation

Pass a resolver that builds the key out of everything the function reads:

const area = _.memoize(
  (width, height) => width * height,
  (width, height) => width + "x" + height
);

Where the arguments are objects, key on the identifying fields rather than on the objects themselves — the default Map cache compares by reference, so two equal objects are two entries.

Notes

Recognised as the library function: _.memoize, lodash.memoize, underscore.memoize, and a bare memoize(…​) in a file that imports lodash, one of its per-method modules, or underscore. Without one of those, a bare memoize is more likely a project helper with a key policy of its own, and assuming otherwise would be a false positive.

A function whose only parameter is a rest parameter is not reported: how many arguments it really takes is a property of its call sites, not of its signature.

© 2026 Xygeni. All rights reserved