Return Value Ignored
ID |
javascript.return_value_ignored |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
dead-code, reliability |
Description
Reports a call to a well-known pure built-in whose return value is discarded because the call stands alone as a whole expression statement: name.trim();, items.filter(isReady);, Object.keys(config);.
JavaScript has no types the engine can lean on here, so purity comes from two curated lists rather than from inference, and both are deliberately narrow.
-
Static built-ins are matched on the namespace and the method:
Math,JSON,Object,Number,ArrayandString. Naming the namespace makes these effectively certain. The mutating members of those namespaces are absent by design —Object.assign,Object.freeze,Object.definePropertyandObject.setPrototypeOfall change the object handed to them, so ignoring what they return is correct. -
Instance methods are matched on the method name alone, and only on a member call:
x.trim(), never a baretrim(s), which would be some local helper. The list holds only names whose mutating counterparts are spelled differently — the in-place array methodssort,reverse,splice,push,fillandcopyWithinare not on it, while their copying siblingstoSorted,toReversedandsliceare.normalizeis left off for the same reason: on a DOM node it merges text children in place.
The call also has to be the last link of its chain and the whole expression of the statement, so items.filter(isReady).forEach(run); and count = items.filter(isReady).length; are not reported — the filtered array is used.
Rationale
// Bad
function normalizeName(name) {
name.trim(); // returns a trimmed copy; `name` is untouched
return name;
}
function readyCount(items, isReady) {
items.filter(isReady); // returns a new array, dropped on the floor
return items.length;
}
-
These operations compute a new value and leave the receiver and the arguments alone, so a statement that drops the result does nothing at all. The line reads as if it changed something, which is why it survives review.
-
JavaScript’s string methods are all non-mutating — strings are immutable — so every
s.someMethod();statement on a string is dead code. -
The array API is the trap:
sortandreversemutate in place,map,filterandslicereturn a copy. Half the methods reward the statement form and half do not, and nothing in the call site says which. -
items.filter(f);written for the side effects offis the specific mistakeforEachexists to avoid.
Remediation
Use the returned value, or switch to the operation that changes the receiver.
// Good
function normalizeName(name) {
return name.trim();
}
function readyCount(items, isReady) {
return items.filter(isReady).length;
}
function run(items, effect) {
items.forEach(effect); // the effectful sibling of `map`
}
If the call really is there only for a side effect inside a callback, for…of or forEach says so; if the value is genuinely unwanted, deleting the statement is the honest fix.