Lodash _.toNumber() method
What you’ll learn
- How
_.toNumber(value)is the raw coercion behind_.toFinite,_.toInteger, and_.toLength. - Why
NaNand±Infinitypass through untouched (unlike_.toFinite). - How object inputs get their
valueOf()called. - The numeric-string tricks: whitespace trimming, hex/binary/octal prefixes, bad-hex detection.
Prerequisites
You’ve used Number() and know the valueOf /toString conversion hooks.
- You’re comfortable distinguishing
NaN,0, andInfinitywhen reasoning about coercion. - Try-it labs load lodash from the CDN.
Overview
The algorithm in five steps: number → return; Symbol → NaN; object → call valueOf() (then fall back to String(other)); non-string → +value; string → trim, check 0x/0b/0o prefixes, parse.
Faithful coercion
NaN, Infinity, and undefined survive—no sanitising.
String prefixes
Parses 0x, 0b, 0o; trims whitespace; rejects bad signed hex.
valueOf hook
Objects with a numeric valueOf() coerce cleanly.
Syntax
_.toNumber(value) - value: the value to convert.
- Returns: a
number. Can beNaNor±Infinity. Throws only forBigInt.
Lodash docs baseline
Four official examples—decimal, tiny, infinite, and numeric string. Notice Infinity stays Infinity.
import toNumber from "lodash/toNumber";
console.log(
"3.2: " + toNumber(3.2) + "\n" + // 3.2
"MIN_VALUE: " + toNumber(Number.MIN_VALUE) + "\n" + // 5e-324
"Infinity: " + toNumber(Infinity) + "\n" + // Infinity (preserved!)
"'3.2' string: " + toNumber("3.2") // 3.2
); Nullish, falsy, and Symbol
A common myth: “_.toNumber turns nullish into 0.” Half-true—null coerces to 0, but undefined coerces to NaN. Symbols also short-circuit to NaN.
import toNumber from "lodash/toNumber";
console.log(
"null: " + toNumber(null) + "\n" + // 0 (Number(null) = 0)
"undefined: " + toNumber(undefined) + "\n" + // NaN (Number(undefined) = NaN)
"'': " + toNumber("") + "\n" + // 0
"true: " + toNumber(true) + "\n" + // 1
"false: " + toNumber(false) + "\n" + // 0
"Symbol(): " + toNumber(Symbol()) // NaN
); String prefixes & valueOf hook
Whitespace trim, three numeric literal prefixes, the “bad signed hex” rejection, and the custom valueOf hook that lets your own objects coerce.
import toNumber from "lodash/toNumber";
const money = { valueOf: () => 7 };
console.log(
"' 7 ' trim: " + toNumber(" 7 ") + "\n" + // 7
"'0x1f' hex: " + toNumber("0x1f") + "\n" + // 31
"'0b11' binary: " + toNumber("0b11") + "\n" + // 3
"'0o17' octal: " + toNumber("0o17") + "\n" + // 15
"'-0x10' bad hex: " + toNumber("-0x10") + "\n" + // NaN (signed hex rejected)
"{ valueOf:()=>7 } obj: " + toNumber(money) // 7
); 📋 _.toNumber vs related conversions
| Input | _.toNumber | _.toFinite | Number() | parseFloat |
|---|---|---|---|---|
undefined | NaN | 0 | NaN | NaN |
Infinity | Infinity | 1.79e+308 | Infinity | Infinity |
'0x1f' | 31 | 31 | 31 | 0 |
'0b11' | 3 | 3 | 3 | 0 |
' 7px ' | NaN | 0 | NaN | 7 |
Pitfalls to avoid
undefined is not 0
_.toNumber(undefined) is NaN. Reach for _.toFinite when you want missing data to default to 0.
Multi-element arrays → NaN
_.toNumber([5]) is 5, but _.toNumber([5, 6]) is NaN because the string fallback produces '5,6'. Same trap as +arr.
BigInt throws
_.toNumber(1n) raises “Cannot convert a BigInt value to a number.” Convert via Number(bigint) first if you can accept precision loss.
❓ FAQ
Summary
- Purpose: the raw number-coercion primitive used by
_.toFinite,_.toInteger,_.toLength, and the relational helpers_.lt/_.gt. - Remember: it can return
NaNor±Infinity. Use_.toFiniteif you need a sanitised number. - Next: see Lodash _.toPlainObject() —
_.toPlainObjectand the remaining Lang helpers.
_.toNumber calls valueOf() on object inputs first—so a tagged value like { valueOf: () => 7 } returns 7. That’s the same hook the + operator uses, just exposed as a named utility.
6 people found this page helpful
