How do I convert a string to a number in JavaScript?

I’m working on a small JavaScript project and I’m stuck converting user input from a string to a number. Some values work, others break my calculations or return NaN. What’s the reliable way to convert strings to numbers in JavaScript, and are there any common pitfalls I should watch out for?

The “reliable way” depends on what kind of number you expect and how strict you want to be.

  1. Quick win for normal numbers

If the string is a plain number:

‘42’
‘3.14’
‘-7’

Use Number:

const n = Number(input)

It returns a number or NaN.

Number(‘42’) // 42
Number(‘3.14’) // 3.14
Number(’ 10 ‘) // 10
Number(‘10px’) // NaN
Number(’‘) // 0
Number(’ ') // 0
Number(‘foo’) // NaN

The empty string turning into 0 often bites people. So you should check input.length first.

  1. Integers only

Use parseInt, but always pass a radix:

const n = parseInt(input, 10)

Examples:

parseInt(‘10’, 10) // 10
parseInt(‘10.5’, 10) // 10
parseInt(‘010’, 10) // 10
parseInt(‘10px’, 10) // 10
parseInt(‘px10’, 10) // NaN

parseInt stops at the first non digit. This is good for stuff like ‘10px’, bad if you expect the whole string to be numeric.

  1. Floats

Use parseFloat:

const n = parseFloat(input)

parseFloat(‘3.14’) // 3.14
parseFloat(‘3.14px’) // 3.14
parseFloat(‘px3.14’) // NaN

Same issue. It accepts partial numbers.

  1. Fast shorthand

The unary plus turns a string into a number:

const n = +input

Examples:

+‘42’ // 42
+‘3.14’ // 3.14
+‘10px’ // NaN
+‘’ // 0

It behaves like Number(input). Use it when you are comfortable with that behavior and you want short code.

  1. Common NaN traps

a) Empty inputs

const input = prompt(‘Enter number’)
const n = Number(input)

If user hits Cancel, input is null. Number(null) is 0. If user enters ‘’, Number(‘’) is 0. That often breaks logic.

Better:

if (input == null || input.trim() === ‘’) {
// handle missing value
} else {
const n = Number(input)
if (Number.isNaN(n)) {
// handle invalid number
}
}

b) Whitespace and commas

Number(’ 123 ') // 123
Number(‘1,234’) // NaN

If your users type “1,234.56”, you need to sanitize first:

const cleaned = input.replace(/,/g, ‘’)
const n = Number(cleaned)

c) Boolean-like strings

Number(‘true’) // NaN
Number(‘false’) // NaN

You need custom logic:

const n = input === ‘true’ ? 1 :
input === ‘false’ ? 0 :
Number(input)

  1. Strict validation pattern

If you want to fail when the whole thing is not a pure number string, combine regex with Number:

function toNumberStrict(str) {
if (typeof str !== ‘string’) return NaN
const trimmed = str.trim()
if (!/^-?\d+(.\d+)?$/.test(trimmed)) return NaN
return Number(trimmed)
}

toNumberStrict(‘42’) // 42
toNumberStrict(‘42a’) // NaN
toNumberStrict(‘3.14’) // 3.14
toNumberStrict(’ 3.14 ') // 3.14

  1. Which one should you use

Most forms or prompts:

const n = Number(input)
if (Number.isNaN(n)) {
// tell user input is invalid
}

If you expect integers only:

const n = Number(input)
if (!Number.isInteger(n)) {
// invalid or not an integer
}

If you accept “10px” style values:

const n = parseInt(input, 10)
if (Number.isNaN(n)) {
// invalid
}

  1. Debugging why your calc breaks

Log both the value and typeof:

console.log(‘input:’, input, ‘type:’, typeof input)
const n = Number(input)
console.log(‘n:’, n, ‘isNaN:’, Number.isNaN(n))

If something turns into NaN, walk back from there:

• Check for empty string, null, undefined
• Check for commas or text like ‘10px’
• Check if trimming fixes it

Once you handle empty input and check Number.isNaN on every conversion, your calculations stop blowing up.

If your calcs are randomly exploding into NaN, the main thing you’re missing is usually validation logic, not just “which function do I call.”

@shizuka covered the basic tools really well (Number, parseInt, parseFloat, unary +). I’d actually say the reliable way is: pick one conversion method, then wrap it in your own small helper that enforces your rules.

Something like:

function toNumberStrict(input) {
  if (input == null) return NaN   // null or undefined

  if (typeof input !== 'string') {
    // optional: allow numbers to pass through
    if (typeof input === 'number') return input
    return NaN
  }

  const trimmed = input.trim()
  if (trimmed === ') return NaN  // don't silently treat empty as 0

  const n = Number(trimmed)
  return Number.isFinite(n) ? n : NaN
}

Usage:

const raw = prompt('Enter a number:')
const value = toNumberStrict(raw)

if (Number.isNaN(value)) {
  alert('That is not a valid number')
} else {
  console.log('OK, value:', value)
}

Key differences from some of what was suggested:

  • I avoid relying on Number(') === 0 or Number(null) === 0. That behavior is technically correct but practically terrible for user input, because “no input” is not the same as zero.
  • I don’t use parseInt / parseFloat for general user input, because '10px' turning into 10 can hide bugs. Great for CSS parsing, bad for “user typed a number in a form.”
  • I insist on Number.isFinite, not just !Number.isNaN, so junk like 'Infinity' does not silently pass as a “valid” number.

If you do need to support stuff like 1,234.56 from users, extend the helper:

function toNumberLocaleish(input) {
  if (input == null) return NaN
  const trimmed = String(input).trim()
  if (trimmed === ') return NaN

  // naive: strip commas
  const cleaned = trimmed.replace(/,/g, ')
  const n = Number(cleaned)
  return Number.isFinite(n) ? n : NaN
}

Then your workflow becomes:

  1. Read raw input.
  2. Convert with one helper function.
  3. Immediately check Number.isNaN(result) or maybe also Number.isFinite(result).
  4. Only after that do any calculations.

If you follow that pattern, you basically stop seeing “random” NaNs: they all get caught at the conversion step instead of leaking into the rest of your code and blowing up 5 lines later.