Menu

JavaScript Type Coercion: Implicit vs Explicit Conversions

How JavaScript coerces values between types — the implicit rules that trip people up, the explicit conversions you should prefer, and when each kicks in.

Two Kinds of Coercion

JavaScript is loose about types. When an operator gets a value of the "wrong" type, the language doesn't throw — it converts. That conversion is called coercion, and it comes in two flavours:

  • Explicit — you ask for it: Number("42"), String(99), Boolean(value).
  • Implicit — an operator triggers it without you writing a conversion: "5" - 2, "" == 0, if (value).

Both end up calling the same underlying conversion rules. The difference is whether you or the language decided to convert. Almost every confusing JavaScript result — "5" + 1 === "51", [] == false, null == undefined — comes from implicit coercion catching you off guard.

index.js
Output
Click Run to see the output here.

The mental model: if you type Number(...) or String(...) you know what you're asking for. If you don't, every operator has its own opinion about what to do — and those opinions are where bugs live.

The Three Target Types

Coercion always converts toward one of three primitive types: string, number, or boolean. (There's a fourth, bigint, but it never gets coerced into from other types automatically.) Everything else about the rules follows from which target an operator is aiming for.

index.js
Output
Click Run to see the output here.

String coercion is the forgiving one — every value has a string form. Notice that objects stringify to the unhelpful "[object Object]", which is why logging an object concatenated with a string ("user: " + user) almost never shows what you wanted. Use JSON.stringify or template literals with specific fields instead.

Coercion to Number

Number coercion is stricter. Strings have to actually look like a number, or you get NaN:

index.js
Output
Click Run to see the output here.

The parenthesised surprises are the ones worth memorising:

  • Empty string and whitespace-only strings become 0, not NaN.
  • null becomes 0, but undefined becomes NaN.
  • An empty array becomes 0; a one-element array coerces that element; a multi-element array becomes NaN.

If you want to parse a number out of a string that has extra characters, use parseInt or parseFloat instead of Number:

index.js
Output
Click Run to see the output here.

Always pass the radix (10) to parseInt. Without it, strings starting with "0x" parse as hex, which is rarely what you meant.

Coercion to Boolean

Boolean coercion is the simplest of the three. A short list of values coerces to false — everything else is true.

The falsy values are:

  • false
  • 0, -0, 0n
  • "" (empty string)
  • null
  • undefined
  • NaN

That's it. Every other value — including "false", "0", [], and {} — is truthy.

index.js
Output
Click Run to see the output here.

The empty-array and empty-object results bite people who came from Python, where empty collections are falsy. In JavaScript, they're truthy — if you want "is this array empty?", check arr.length === 0 explicitly.

Boolean coercion runs whenever a value appears where a boolean is expected: if (...), while (...), the ternary ? :, and the logical operators &&, ||, !.

The + Operator Is a Special Case

Most arithmetic operators force their operands to numbers. + is different — if either side is a string, + does string concatenation. Otherwise it does numeric addition.

index.js
Output
Click Run to see the output here.

The evaluation is left-to-right. 1 + 2 + "3" first computes 1 + 2 = 3, then 3 + "3" = "33". But "1" + 2 + 3 starts stringy and stays stringy: "12", then "123".

This is why building strings with + is fragile. Template literals don't have this problem:

index.js
Output
Click Run to see the output here.

The template literal evaluates count + 1 as its own numeric expression, then interpolates the result. No surprise coercion.

Prefer Explicit Conversions

When you need to convert a type, say so. It costs a few characters and removes all ambiguity for the next reader:

index.js
Output
Click Run to see the output here.

Same for booleans. !!value works and is common, but Boolean(value) says exactly what it does:

index.js
Output
Click Run to see the output here.

A reasonable rule: use explicit conversions in application logic, and save the short forms (+x, !!x) for places where brevity matters and the intent is obvious from context.

The == Operator Leans on Coercion Hard

The equality operators are the biggest source of coercion surprises. == coerces before comparing; === doesn't.

index.js
Output
Click Run to see the output here.

Each true above is the result of a multi-step coercion chain most developers can't recite from memory. That's the problem — code that works by accident is code that breaks later. We'll get into the full equality rules on the next page; for now, the takeaway is: use === by default, and reach for == only for the specific idiom x == null (which catches both null and undefined).

Putting It Together

A worked example showing where coercion helps and where it hurts:

index.js
Output
Click Run to see the output here.

Notice the second call. Number("") returns 0, not NaN — so parsePrice("") returns 0, which probably isn't what a user of this function would want. If empty input should be rejected, add an explicit check:

index.js
Output
Click Run to see the output here.

Knowing which values coerce to 0 vs NaN is exactly the kind of thing that saves you from a subtle bug downstream.

What to Take Away

  • Coercion converts to string, number, or boolean depending on the operator.
  • + with any string becomes concatenation; every other arithmetic operator coerces to number.
  • Falsy values are a fixed short list — memorise it. Everything else is truthy, including [] and {}.
  • Number("") is 0, Number([]) is 0, Number(null) is 0 — but Number(undefined) is NaN. These show up in real bugs.
  • Prefer Number(x), String(x), Boolean(x) over clever implicit tricks. Future-you will be grateful.

Next: Equality Operators

Everything coercion does in comparisons lives inside ==. The next page walks through == vs === vs Object.is, the one idiom where == is still useful, and why linters default to flagging the loose form.

Frequently Asked Questions

What is type coercion in JavaScript?

Type coercion is JavaScript automatically converting a value from one type to another — a number becoming a string, a string becoming a number, or anything becoming a boolean. It happens implicitly when operators like +, ==, or if see a value that isn't the type they expect, and explicitly when you call Number(x), String(x), or Boolean(x) yourself.

What's the difference between implicit and explicit coercion?

Explicit coercion is when you call a conversion function on purpose: Number("42"), String(99), Boolean(value). Implicit coercion is when an operator triggers conversion behind your back: "5" - 2 gives 3, "5" + 2 gives "52". Explicit is readable and predictable; implicit is the source of most "why is this NaN" bugs.

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

Use Number("42") for a strict conversion (returns NaN if the string isn't a valid number), or parseInt("42px", 10) / parseFloat("3.14em") if you want to read a number from the front of a messier string. The unary + operator (+"42") does the same as Number() but is easier to miss when skimming code.

Why does [] + [] return an empty string?

The + operator has no meaningful numeric operation for two arrays, so JavaScript coerces both to strings. Arrays stringify by joining their elements with commas, and an empty array joins to "". So [] + [] becomes "" + "", which is "". It's a fun party trick and a good reason to never rely on + with non-primitives.

Learn to code with Coddy

GET STARTED