Lodash _.subtract() method

Beginner
⏱️ 6 min read
📚 Updated: May 2026
🎯 3 Code examples
🚀 3 Try-it labs
Lodash

What you’ll learn

  • How _.subtract is built with createMathOperation((a, b) => a - b, 0)—sharing the factory with _.add, _.multiply, and _.divide.
  • The non-commutative undefined trap: _.subtract(undefined, 5) returns 5, not -5.
  • That null coerces to 0 and produces the correct sign—making it the safer placeholder.
  • Why stringy numeric inputs coerce correctly (no concatenation trap like _.add).
  • How to use _.subtract inside reduce for running differences, and why BigInt throws.

Prerequisites

Skim _.add() first—same factory, identity 0. The factory’s undefined rules behave well for _.add (commutative) but bite for _.subtract.

  • Commutativity: a + b == b + a, but a - b != b - a. Matters for the undefined rule.
  • Native - coercion: always tries to make a number; never concatenates strings.

Overview

The implementation is two lines: createMathOperation((a, b) => a - b, 0). The factory’s rules: both undefined0 (identity); one undefinedreturn the other operand (no math runs); otherwise coerce via baseToNumber (or baseToString if either is a string) and apply -. The “return the other operand” rule is mathematically correct for + and * but produces the wrong sign for -.

Identity is 0

Same as _.add. Useful for reduce-on-empty.

Non-commutative trap

_.subtract(undefined, 5) returns 5, not -5. The factory wasn’t designed for this case.

No precision fix

0.3 - 0.2 still produces 0.09999…. Lodash uses native -.

Syntax

javascript
_.subtract(minuend, subtrahend)
  • minuend: the number to subtract from.
  • subtrahend: the number to subtract.
  • Returns: number—the difference. 0 if both inputs are undefined; the lone operand untouched if one is undefined.
1

Basics — numbers, strings, precision

The docs example plus the common stringy-input case (which works numerically, unlike _.add) and the floating-point reality.

javascript
import subtract from "lodash/subtract";

console.log(subtract(6, 4));            // 2   (docs example)
console.log(subtract(10, 5));            // 5
console.log(subtract(15, 7));            // 8

// Stringy numeric inputs coerce numerically (no '+' trap)
console.log(subtract("10", "3"));        // 7
console.log(subtract(10, "3"));          // 7
console.log(subtract("abc", 3));         // NaN

// Map a constant adjustment over an array
console.log([10, 20, 30, 40].map(v => subtract(v, 5))); // [5, 15, 25, 35]

// Floating-point: Lodash does NOT fix precision
console.log(subtract(0.3, 0.2));         // 0.09999999999999998
console.log(subtract(0.1 + 0.2, 0.3));   // 5.551115123125783e-17
Try it Yourself
2

The undefined sign-flip trap

The most surprising thing about _.subtract: undefined on the left side does not become 0 — the factory just returns the right operand. So 0 − 5 never happens. Use null instead when you need a missing minuend to behave like zero.

javascript
import subtract from "lodash/subtract";

// Both undefined: identity
console.log(subtract(undefined, undefined)); // 0

// One undefined: returns the OTHER operand untouched (no math!)
console.log(subtract(undefined, 5));         // 5    BUG-PRONE: expected -5
console.log(subtract(5, undefined));         // 5    OK: 5 - 0 would also be 5

// null coerces to 0 -> correct math
console.log(subtract(null, 5));              // -5   correct
console.log(subtract(5, null));              // 5
console.log(subtract(null, null));           // 0

// Defensive helper
function safeSubtract(a, b) {
  return subtract(a ?? 0, b ?? 0);  // treat both undefined & null as 0
}
console.log(safeSubtract(undefined, 5));     // -5
console.log(safeSubtract(5, undefined));     // 5
Try it Yourself
3

Reduce, edge cases, and BigInt

Use _.subtract as a reduce callback for running differences. Identity is 0, so empty-array reduce-with-initial-value works cleanly. BigInt throws.

javascript
import subtract from "lodash/subtract";

// Running differences
console.log([100, 10, 20, 30].reduce(subtract));      // 40   (100 - 10 - 20 - 30)
console.log([10, 20, 30].reduce(subtract, 100));      // 40
console.log([].reduce(subtract, 100));                 // 100  (initial value untouched)

// Infinity & NaN propagation
console.log(subtract(Infinity, 1));                   // Infinity
console.log(subtract(Infinity, Infinity));            // NaN
console.log(subtract(NaN, 5));                         // NaN

// Sign preservation: -0 vs 0
console.log(subtract(0, 0));                           // 0
console.log(subtract(-0, 0));                          // -0

// BigInt: throws
try {
  console.log(subtract(5n, 2n));
} catch (err) {
  console.log("Threw:", err.message);                  // "Cannot convert a BigInt value to a number"
}

// Native works for BigInt
console.log(5n - 2n);                                  // 3n
Try it Yourself

📋 _.subtract vs native -

Input_.subtract(a, b)a - bNotes
6, 422Same.
undefined, undefined0NaNLodash returns identity.
undefined, 55NaNLodash returns the lone operand—wrong sign for subtraction.
5, undefined5NaNSame factory rule; mathematically “5 - 0” would also be 5, so it’s consistent here.
null, 5-5-5Both treat null as 0.
"10", "3"77Both coerce numerically (- never concatenates).
0.3, 0.20.099…80.099…8Same float-precision result.
5n, 2nthrows3nNative - supports BigInt; Lodash does not.

Pitfalls to avoid

undefined

Sign-flip trap

_.subtract(undefined, 5) is 5, not -5. If the minuend might be undefined, coalesce to 0 first (a ?? 0) or use null instead.

Precision

Not a precision fix

_.subtract(0.3, 0.2) is 0.09999999999999998. The old reference’s “addresses precision challenges” framing is wrong—Lodash just wraps -.

null vs undefined

Behave differently

null coerces to 0 (correct math). undefined short-circuits (returns the other operand). Don’t treat them as interchangeable.

BigInt

Throws

Use the native - operator for BigInt math.

Non-numeric strings

Silent NaN

Numeric strings work ("10" - 3 = 7) but "abc" gives NaN with no error. Validate when input is untyped.

❓ FAQ

Because of how the shared createMathOperation factory handles undefined operands. The factory returns the 'other' operand untouched whenever one side is undefined—this is correct for the commutative siblings (_.add(undefined, 5) returning 5, _.multiply(undefined, 5) returning 5) but produces the wrong sign for non-commutative subtraction. Use null instead of undefined for missing minuends; null correctly coerces to 0, so _.subtract(null, 5) returns -5.
No. _.subtract(0.3, 0.2) returns 0.09999999999999998, identical to native 0.3 - 0.2. The factory uses the native - operator. If precision matters (especially for money), scale to integers first or use a decimal library like decimal.js.
Numeric strings coerce numerically: _.subtract('10', '3') is 7, _.subtract(10, '3') is 7. Unlike _.add (which would concatenate to '103'), the - operator always tries to make a number. Non-numeric strings like 'abc' produce NaN.
No—it throws Cannot convert a BigInt value to a number. Use the native - operator directly: 5n - 2n is 3n.
Mostly no. The one nicety is the undefined identity: arr.reduce(_.subtract) works on a one-element array (returns that element), and arr.reduce(_.subtract, 0) returns 0 on an empty array instead of throwing. For most code, just use - directly.
Yes: [100, 10, 20, 30].reduce(_.subtract) returns 40 (i.e. 100 - 10 - 20 - 30). With an initial value, [10, 20, 30].reduce(_.subtract, 100) is 40. Empty array with initial value returns the initial value untouched.

Summary

  • Purpose: pairwise subtraction built on createMathOperation(-, 0).
  • Remember: _.subtract(undefined, 5) is 5 (sign-flip trap); null coerces to 0; stringy numerics coerce numerically; non-numeric strings → NaN; BigInt throws; precision unfixed.
  • Next: Lodash _.sum(), or read the official Lodash docs for _.subtract.
Did you know?

_.subtract(undefined, 5) returns 5, not -5. The createMathOperation factory short-circuits whenever one operand is undefined and returns the other operand untouched—sound for commutative _.add and _.multiply, mathematically wrong for non-commutative _.subtract. Use null as a placeholder (it coerces to 0 properly) or guard before calling.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

6 people found this page helpful