parseFloat with a Comma Decimal Separator: Why It Returns the Wrong Number
parseFloat does not fail on numbers written with a comma decimal separator. It does something worse: it returns a wrong number.
What parseFloat actually does
parseFloat reads characters from the start of the string while they look like an English number, then stops and returns whatever it has. It never reports an error for the rest of the string.
parseFloat("1,5"); // 1 (stops at ",")
parseFloat("1.234,56"); // 1.234 (stops at the second ".")
parseFloat("1'234.56"); // 1 (stops at "'")
parseFloat("12,34,567.89"); // 12 (stops at ",")
parseFloat("R$ 10,00"); // NaN (starts with "R")A wrong number is more dangerous than NaN: 1.234 passes every isNaN check and quietly ends up in your database, invoice or chart.
Number() is stricter, but not smarter
Number("1,5"); // NaN
Number("1.234,56"); // NaN
Number("1 234"); // NaNNumber rejects the whole string, which is safer, but it still only understands one format: a dot as the decimal separator and no grouping at all.
The fix
Parse with the locale the number was written in. numberparrot gets the separators from Intl.NumberFormat and validates the whole string:
import { parse } from "numberparrot";
parse("1,5", "pt-BR"); // 1.5
parse("1.234,56", "pt-BR"); // 1234.56
parse("1'234.56", "de-CH"); // 1234.56
parse("12,34,567.89", "en-IN"); // 1234567.89
// Strict mode throws with a reason instead of returning NaN
parse("1,23", "en-US", { strict: true }); // NumberParseError: INVALID_GROUPINGComparison
| Input | Locale | parseFloat | Number | numberparrot |
|---|---|---|---|---|
1,5 | pt-BR | 1 | NaN | 1.5 |
1.234,56 | de-DE | 1.234 | NaN | 1234.56 |
1 234,56 | fr-FR | 1 | NaN | 1234.56 |
-1.234,56 | it-IT | -1.234 | NaN | -1234.56 |
Install
npm install numberparrotZero dependencies, ESM and CommonJS, TypeScript types included. Works in Node.js 18+, Deno, Bun and browsers. Try it in the playground.