JavaScriptBeginner

JavaScript Type Coercion: Implicit Conversion Explained

Understand how JavaScript silently converts types with +, -, comparisons and boolean checks, so you can predict results and avoid sneaky bugs.

All JavaScript lessons

What you will learn

In the last lesson you changed types on purpose with Number(), String() and Boolean(). But JavaScript also changes types by itself, without asking you. This is called type coercion. It explains why "5" + 3 is "53" but "5" - 3 is 2, and why if ("hello") works. By the end of this lesson you will be able to predict the result of such code, and know how to stay in control.

Conversion vs coercion

Both words mean “changing a value from one type to another”. The difference is who does it.

Who converts? Example
Explicit conversion (type casting) You, using a function Number("5")
Implicit conversion (type coercion) JavaScript, automatically "5" - 3
// Explicit: you decided
const a = Number("5") + 3;
console.log(a);   // 8

// Implicit: JavaScript decided
const b = "5" - 3;
console.log(b);   // 2

Why does coercion happen?

Operators expect certain types. The - operator only makes sense with numbers, so when you give it a string, JavaScript tries to turn that string into a number instead of throwing an error. It is helpful when it guesses right and confusing when it guesses differently from what you wanted.

JavaScript coerces values into one of only three types:

  1. String (when joining text)
  2. Number (when doing maths or comparing)
  3. Boolean (when making a yes/no decision)

Learn the rules for these three, and you understand coercion.

1. Coercion to string: the + operator

The + operator is special because it does two jobs: add numbers and join strings. The rule is simple:

If either side is a string, + joins them as text. Otherwise it adds numbers.

console.log(5 + 3);         // 8      (both numbers: add)
console.log("5" + 3);       // "53"   (one is a string: join)
console.log("Age: " + 20);  // "Age: 20"

Left to right matters

JavaScript solves + one pair at a time, from left to right:

console.log(1 + 2 + "3");   // "33"   (1+2 = 3 first, then "3" + "3")
console.log("1" + 2 + 3);   // "123"  (text from the start: everything joins)
console.log("Total: " + 5 + 5);     // "Total: 55"
console.log("Total: " + (5 + 5));   // "Total: 10"  (brackets fix it)

Whenever you mix text and numbers in a +, use brackets or a template literal to make your intention clear.

Other values turn into text too

When joined with a string, every value is converted to its text form:

console.log("Value: " + true);        // "Value: true"
console.log("Value: " + null);        // "Value: null"
console.log("Value: " + undefined);   // "Value: undefined"
console.log("Items: " + [1, 2, 3]);   // "Items: 1,2,3"
console.log("User: " + {});           // "User: [object Object]"

The last line is a common sign of a bug: you wanted to show an object, but JavaScript turned it into the useless text [object Object].

2. Coercion to number: -, *, /, %, **

Unlike +, these operators have only one job (maths), so they always convert both sides to numbers:

console.log("10" - 3);      // 7
console.log("10" * "2");    // 20
console.log("20" / 4);      // 5
console.log("7" % "4");     // 3
console.log("2" ** "3");    // 8

If the text cannot be understood as a number, the result is NaN (Not a Number):

console.log("hello" - 1);   // NaN
console.log("12px" * 2);    // NaN

How values become numbers

Value Becomes Notes
"42" 42 Normal number text
" 42 " 42 Spaces around are ignored
"3.14" 3.14
"" (empty string) 0 Surprise!
" " (only spaces) 0
"12px" NaN Letters spoil it
true 1
false 0
null 0
undefined NaN
[] (empty array) 0
[5] 5 One-item array
[1, 2] NaN
console.log(true + 1);        // 2
console.log(null + 1);        // 1
console.log(undefined + 1);   // NaN
console.log(true + true);     // 2

Remember: null becomes 0, but undefined becomes NaN. This difference trips up many people.

The unary plus +

A single + placed in front of a value is a quick way to convert it to a number. It is the shortest form of Number():

console.log(+"42");     // 42
console.log(+"3.14");   // 3.14
console.log(+true);     // 1
console.log(+"");       // 0
console.log(+"abc");    // NaN

It is used a lot, but Number("42") is clearer for beginners to read.

3. Coercion in comparisons

Greater than and less than

With >, <, >= and <=:

  • If one side is a number, the other side is converted to a number.
  • If both sides are strings, they are compared letter by letter like in a dictionary (not as numbers).
console.log("10" > 5);      // true    (text becomes 10, then 10 > 5)
console.log(2 < "10");      // true

console.log("10" > "9");    // false!  (both are text: "1" comes before "9")
console.log("apple" < "banana");   // true
console.log("a" < "B");     // false   (small letters come after capital letters)

The "10" > "9" result is a classic bug when sorting or comparing numbers that came from inputs. Convert them first.

Equality: == vs ===

=== never coerces. If the types are different, the answer is false. == does coerce, using these rules:

Case Rule Example
Same type Compare normally "a" == "a" is true
Number and string String becomes a number 5 == "5" is true
Boolean and anything Boolean becomes a number (1 or 0) first true == "1" is true
null and undefined Equal to each other, and to nothing else null == undefined is true, null == 0 is false
Object and primitive Object becomes a primitive [1] == 1 is true
console.log(5 == "5");           // true
console.log(true == "1");        // true
console.log("0" == false);       // true
console.log("" == 0);            // true
console.log(null == undefined);  // true
console.log(null == 0);          // false
console.log([] == false);        // true
console.log(NaN == NaN);         // false

Some of those are very unexpected, which is why you learned to use ===:

console.log(5 === "5");          // false
console.log("0" === false);      // false
console.log([] === false);       // false

Tip: The simple rule is: use === and !== for equality. Then the equality coercion rules never matter, and you only need to understand them to read other people’s code.

4. Coercion to boolean: truthy and falsy

Anywhere JavaScript needs a yes or no answer, it converts the value to a boolean. These places are called boolean contexts:

  • the condition of an if statement
  • the ! (NOT) operator
  • the && and || operators
  • the condition of a while loop and a ternary ? :
if ("hello") {
  console.log("This runs, because non-empty text is truthy");
}

if (0) {
  console.log("This never runs");
}

Every value is either truthy (becomes true) or falsy (becomes false).

The falsy values (memorise these 8)

Boolean(false);       // false
Boolean(0);           // false
Boolean(-0);          // false
Boolean(0n);          // false  (BigInt zero)
Boolean("");          // false  (empty string)
Boolean(null);        // false
Boolean(undefined);   // false
Boolean(NaN);         // false

Everything else is truthy. That includes some values that look “empty” or “false”:

Boolean("0");        // true  (text with a character in it)
Boolean("false");    // true  (it is just text)
Boolean(" ");        // true  (a space is a character)
Boolean([]);         // true  (empty array)
Boolean({});         // true  (empty object)
Boolean(-1);         // true

The double NOT trick !!

! converts to boolean and flips it. Two of them flip it back, leaving you with the boolean version of the value:

console.log(!!"hello");   // true
console.log(!!0);         // false
console.log(!!"0");       // true

Boolean(value) does the same thing, and many developers find it easier to read.

Truthy is not the same as == true

A truthy value is not always equal to true:

const items = [];

if (items) {
  console.log("An empty array is truthy");   // runs
}

console.log(items == false);    // true  (very confusing!)

The array is truthy in an if, but loosely equal to false in ==, because == follows a different set of rules (it converts to numbers). That is another reason to avoid ==.

Logical operators return real values

&& and || do not always return true or false. They return one of the original values, after testing it as a boolean:

console.log("" || "Guest");     // "Guest"   (first truthy value, or the last one)
console.log("Aman" || "Guest"); // "Aman"
console.log(0 || 10);           // 10
console.log("a" && "b");        // "b"       (both truthy: gives the last one)
console.log(null && "b");       // null      (stops at the first falsy one)

Real-life use cases

Use case 1: reading form inputs

The value of an input box is always a string, even if the user types a number. This is the number one place where coercion causes bugs.

<input id="num1" type="text" value="5">
<input id="num2" type="text" value="3">
<button id="add">Add</button>
<p id="result"></p>
const num1 = document.getElementById("num1");
const num2 = document.getElementById("num2");
const result = document.getElementById("result");

document.getElementById("add").addEventListener("click", function () {
  // Wrong: "5" + "3" joins the text
  console.log(num1.value + num2.value);                 // "53"

  // Right: convert first
  console.log(Number(num1.value) + Number(num2.value)); // 8

  result.textContent = Number(num1.value) + Number(num2.value);
});

Using - or * would have worked by accident, but + does not. Always convert input values explicitly.

Use case 2: checking whether the user typed something

Truthy and falsy make “is there any text?” checks short:

const userName = "";

if (userName) {
  console.log("Hello, " + userName);
} else {
  console.log("Please enter your name");
}

An empty string is falsy, so the else branch runs. One catch: a name of only spaces (" ") is truthy. Clean it with .trim() first (strings lesson).

Use case 3: default values

const nickname = "";
const displayName = nickname || "Guest";
console.log(displayName);   // "Guest"

Be careful when 0 is a valid value:

const quantity = 0;
console.log(quantity || 1);    // 1  (wrong! the user chose 0)
console.log(quantity ?? 1);    // 0  (right)

You will see ?? in detail in the optional-chaining lesson.

Use case 4: removing falsy values from a list

Boolean can be passed as a filter. This is a handy one-liner that you will understand fully in the array lessons:

const data = [0, 1, "", "hello", null, undefined, NaN, false, 2];
const cleaned = data.filter(Boolean);
console.log(cleaned);   // [1, "hello", 2]

A fun example: “banana”

console.log("ba" + +"a" + "a");   // "baNaNa"

Step by step: +"a" converts the text "a" to a number, which is NaN. Then "ba" + NaN joins as text: "baNaN", and finally "a" is added. Funny, but also a good test of whether you understand coercion.

Best practices

  • Convert on purpose. Use Number(), String() and Boolean() when you want a different type, so a reader can see your intention.
  • Use === and !==.
  • Be careful with + whenever one of the values might be a string, especially values from inputs, prompt() or URLs.
  • Learn the 8 falsy values. If you know them, truthy and falsy checks are never a surprise.
  • Do not use clever tricks just to save a few characters. Code is read more often than written.

Common mistakes

  • Adding input values without converting. "5" + "3" is "53".
  • Assuming "0" or "false" is falsy. Any non-empty string is truthy.
  • Assuming [] and {} are falsy. They are truthy. Check .length for arrays.
  • Comparing numbers as strings. "10" < "9" is true because strings compare letter by letter.
  • Using == null or == 0 without knowing the rules. null == 0 is false, even though null becomes 0 in maths.
  • Printing an object with +. "User: " + user gives [object Object]. Use JSON.stringify(user) or log the object itself.
  • Forgetting that || treats 0 and "" as missing values.

Practice

  1. Predict the output of each line, then check in the editor:

    console.log("3" + 4 + 5);
    console.log(3 + 4 + "5");
    console.log("10" - "4");
    console.log("5" * "5");
    console.log(true + 1);
    console.log(null + 5);
    console.log(undefined + 5);
  2. Click Practice in Editor and run the Add button. Fix the code so that 5 and 3 give 8, not 53.

  3. Which of these are truthy? Check each with Boolean(...): "0", 0, [], "", " ", null, -1, "false", NaN, {}.

  4. Explain, without running it, why "10" > "9" is false but "10" > 9 is true.

  5. Use || to print "Anonymous" when a variable username is an empty string, and print the real name when it is filled in.

  6. Use .filter(Boolean) to clean this array: ["Riya", "", "Karan", null, "Neha", undefined].

Recap

  • Type coercion is JavaScript converting types automatically. Conversion you do yourself is explicit, and the automatic one is implicit.
  • Values are coerced into a string, a number or a boolean.
  • + joins text if either side is a string. All other math operators (- * / % **) convert to numbers.
  • "" and null become 0, undefined becomes NaN, and true becomes 1.
  • In comparisons, a mix of a number and a string compares as numbers, but two strings compare as text ("10" > "9" is false).
  • == coerces and gives strange results. === does not. Use ===.
  • There are 8 falsy values: false, 0, -0, 0n, "", null, undefined, NaN. Everything else is truthy, even "0", [] and {}.
  • Input values are always strings, so convert them before maths.
  • Next you will work with strings: indexing, methods and template literals.