How Lodash _.add Handles String Concatenation

This article examines how the Lodash library processes numerical strings in its _.add method. It explores the internal architecture behind createMathOperation, details how type-checking dictates string concatenation versus numeric addition, and explains why Lodash preserves standard JavaScript addition semantics for string primitives while applying explicit conversions like baseToNumber for non-primitive inputs.

The Architecture of _.add

In Lodash, _.add is not an isolated function containing manual mathematical logic. Instead, it is generated using an internal higher-order factory function called createMathOperation:

const add = createMathOperation((augend, addend) => augend + addend, 0);

When you invoke _.add(augend, addend), the call is routed through createMathOperation. This wrapper standardizes input handling, default fallbacks, and type coercion across mathematical methods like add, subtract, multiply, and divide.

How Type Resolution Operates

The internal implementation of createMathOperation determines whether to treat arguments as strings or numbers before invoking the mathematical operator. The core branching logic functions as follows:

if (typeof value === 'string' || typeof other === 'string') {
  value = baseToString(value);
  other = baseToString(other);
} else {
  value = baseToNumber(value);
  other = baseToNumber(other);
}
return operator(value, other);

Because of this conditional check:

  1. Primitive Numerical Strings Are Concatenated: If either argument has a primitive typeof value of 'string', Lodash intentionally invokes baseToString on both arguments. When passed to (augend, addend) => augend + addend, JavaScript performs standard string concatenation. For example, _.add('20', '5') produces '205', not 25. Lodash deliberately mirrors native JavaScript + semantics rather than forcibly coercing string primitives into numbers.
  2. Non-String Values Route to baseToNumber: If neither argument evaluates to 'string' via typeof, execution branches to baseToNumber. This includes primitives like numbers, booleans, and null, as well as boxed object types.

Preventing Concatenation for Non-Primitive String Objects

While primitive strings are concatenated, Lodash prevents concatenation when numerical strings are wrapped as objects (e.g., Object('20') or new String('20')).

In JavaScript:

Object('20') + Object('5'); // Evaluates to "205" natively due to ToPrimitive conversion

In Lodash:

  1. The check typeof value === 'string' evaluates to false because the type of a boxed string object is 'object'.
  2. Both arguments bypass the baseToString branch and enter the else branch.
  3. Each argument is processed by baseToNumber, which extracts the primitive numeric value using valueOf() or numeric parsing.
  4. The underlying addition operator receives two numeric primitives: operator(20, 5).
  5. The result is 25, effectively circumventing native string concatenation.

Safe Coercion with baseToNumber

When inputs enter the numeric branch, Lodash avoids raw JavaScript coercion (such as +val or Number(val)) to prevent runtime exceptions. The internal baseToNumber helper handles edge cases safely:

Summary of Behavior

Lodash's _.add avoids unexpected concatenation exclusively through strict typeof boundary checks: