Lodash _.cond with Overlapping Truthy Predicates

When using the _.cond method in Lodash, providing pairs with overlapping truthy predicates results in the execution of only the first matching predicate and its corresponding transformer function. Because Lodash evaluates condition-action pairs sequentially from the beginning of the array to the end, it short-circuits upon encountering the first truthy check, completely ignoring any subsequent matching conditions.

How Lodash Evaluates _.cond

The _.cond method accepts an array of pairs, where each pair consists of a predicate function and a transform function:

_.cond([[predicate1, transform1], [predicate2, transform2], ...]);

When the generated function is called with arguments, Lodash iterates through the pairs in their defined index order:

  1. It invokes the predicate function with the supplied arguments.
  2. If the predicate returns a truthy value, Lodash immediately invokes the corresponding transform function with the same arguments and returns its result.
  3. Once a match is resolved, iteration terminates immediately without evaluating the remaining predicates.
  4. If no predicate returns a truthy value, the function returns undefined.

Example of Overlapping Predicates

Consider a scenario where a number can satisfy multiple conditions, such as being greater than zero and greater than ten:

const _ = require('lodash');

const classifyNumber = _.cond([
  [(n) => n > 0,  (n) => `${n} is greater than 0`],
  [(n) => n > 10, (n) => `${n} is greater than 10`],
  [_.stubTrue,    (n) => `${n} is 0 or negative`]
]);

console.log(classifyNumber(15));
// Output: "15 is greater than 0"

Even though 15 > 10 is true, Lodash encounters (n) => n > 0 first. Because 15 > 0 is truthy, the evaluation halts, and the function returns "15 is greater than 0". The second predicate (n) => n > 10 is never called.

Practical Implications

Because evaluation order dictates which transform runs, proper ordering of predicate pairs is critical:

const classifyNumberCorrected = _.cond([
  [(n) => n > 10, (n) => `${n} is greater than 10`],
  [(n) => n > 0,  (n) => `${n} is greater than 0`],
  [_.stubTrue,    (n) => `${n} is 0 or negative`]
]);

console.log(classifyNumberCorrected(15));
// Output: "15 is greater than 10"