JavaScript rarely refuses an operation. Add a number to a string, compare a boolean with an array: instead of stopping, the language converts one of the two and carries on. That mechanism is called coercion.
It explains most of the puzzling results people hit in their first months, and it is quickly mastered: the rules are few, they are just rarely taught in one place.
Definition
Coercion is the automatic conversion of a value to another type, decided by the language based on the operation requested. It is implicit when it happens on its own, and explicit when the developer triggers it with a call.
// Implicit: nobody asked for this
console.log("5" + 3); // "53" the number becomes a string
console.log("5" - 3); // 2 the string becomes a number
// Explicit: the conversion is written down
console.log(Number("5") + 3); // 8
console.log(String(5) + 3); // "53"The difference between the first two lines comes down to one detail: the + operator both adds and concatenates. As soon as one of the two values is a string, it picks concatenation. The -, * and / operators carry no such ambiguity and always convert toward numbers.
The three possible destinations
Every coercion leads to one of three types, and the context is enough to know which.
| Context | Conversion | Example |
|---|---|---|
Concatenation with + | To String | 1 + "a" gives "1a" |
| Arithmetic, comparison | To Number | "10" * 2 gives 20 |
Condition, !, && | To Boolean | see Truthy and falsy |
console.log(Number("")); // 0
console.log(Number(null)); // 0
console.log(Number(undefined));// NaN
console.log(Number(true)); // 1
console.log(Number("49 usd")); // NaNA failed conversion raises no error: it produces NaN, which then spreads silently through every following calculation. A total displayed as NaN almost always comes from an unconverted input.
Protecting yourself without fighting the language
Three habits remove nearly every surprise.
- Compare with three equals signs. Strict equality (===) converts nothing, whereas Loose equality (==) applies rules no developer remembers in full.
- Convert inputs at the boundary. A form field, a network response, a URL parameter: everything arrives as text. Convert once, on the way in, rather than ten times further down.
- Check the result, not the source.
Number.isNaN(value)right after conversion tells you immediately whether the input was usable.
Frequently asked questions
Why is 1 == "1" true?
Because loose equality converts before comparing: the string becomes the number 1, and the two match. With Strict equality (===), types are compared first and the result is false. That is why the strict version is the default recommendation in every style guide.
Should I use Number() or parseInt()?
Number("49 usd") gives NaN while parseInt("49 usd", 10) gives 49, because parseInt reads while the characters are digits then stops. Prefer Number() when the value must be entirely valid, and parseInt() when you deliberately accept a numeric prefix.
Is coercion a flaw in the language?
It is a deliberate design choice, inherited from a time when the language had to stay forgiving inside a web page. It carries a real cost on large projects, and that is exactly what TypeScript corrects by checking types before execution. The language itself never changed on this point, so as not to break the existing web.