DEV Community

Cover image for Unlocking JavaScript Type Coercion Magic
Shourov Rahman
Shourov Rahman

Posted on • Originally published at shourovrahman.hashnode.dev

Unlocking JavaScript Type Coercion Magic

Type Coercion

What is Type Coercion?

The terms type coercion, type conversion, type casting, and type juggling all refer to the process of converting one data type to another. This process is extremely important in computer science and can be found in almost every programming language.  

Different Types of Type Coercion?

There are two types of coercion available in JavaScript. They are implicit type coercion and explicit type coercion.

Implicit Type Coercion is not intentional. This type of coercion is done by Javascript itself. The Developer has no control over implicit type coercion. Most of the unexpected behavior (80%) happens in JavaScript by implicit type coercion. Some examples are:

console.log(2 * "5") // 10
console.log("12" - "10") // 2
console.log(true + true) // 2
console.log(10 * [6]) // 60
Enter fullscreen mode Exit fullscreen mode

Explicit Type Coercion is intentional and done by the developers. Developers have full control over explicit type coercion. The code behavior of explicit type coercion is obvious and expected. Some examples are:

// Number to String
console.log(String(123)); // "123"

// Number to Boolean
console.log(Boolean(2)); // true

// String to Number
console.log(Number("123")); // 123
Enter fullscreen mode Exit fullscreen mode

Whether it is implicit or explicit type coercion, JavaScript can only convert/coerces to the string, number, and Boolean primitive types. There’s no way in JavaScript to coerce a value type to an object or function.

Implicit Type Conversion/Coercion Based on Operator

Addition Operator (+) Implicit Type Conversion/Coercion

In JavaScript, the "+" symbol is used for addition. The "+" operator performs calculations from left to right. Here are some examples of implicit type coercion using the addition operator, along with their explanations.

Note: You will see comments like the following. Here nested comments are same-line comments. I wrote nested comments for enhancing readability.

// "+" operator work left to right so that
  // first it add two number and then convert 
  // them to string
// ==> 18 + "number"
// ==> "18number"
Enter fullscreen mode Exit fullscreen mode
// "+" operator work left to right so that first it add two number and then convert them to string
// ==> 18 + "number"
// ==> "18number"
Enter fullscreen mode Exit fullscreen mode
console.log(true + false); // 1
// true coerces to 1 and false coerces to 0
// ==> 1 + 0
// ==> 1

console.log(true + true); // 2
// true coerces to 1 and false coerces to 0
// ==> 1 + 1
// ==> 2

console.log(false + false); // 0
// true coerces to 1 and false coerces to 0
// ==> 0 + 0
// ==> 2

console.log("1" + 1); // "11"
// "+" operator work left to right
// ==> "1" + 1
// ==> "11"

console.log("4" + true); // "4true"

// Exception: Symbol cannot convert to string
console.log("" + Symbol("my symbol")); 
// TypeError: Cannot convert a Symbol value to a string

console.log("number" + 15 + 3); // "number153"
// "+" operator work left to right
// ==> "number15" + 3
// ==> "number153"

console.log(15 + 3 + "number"); // "18number"
// "+" operator work left to right so that
  // first it add two number and then convert 
  // them to string
// ==> 18 + "number"
// ==> "18number"

console.log("foo" + +"bar"); // "fooNaN"
// Here (+"bar"), "+" operator act like 
  // unary plus operator, which tries to 
  // convert its operand into a number. 
  // Since the operand is the string "bar", 
  // which cannot be directly converted into a number, 
  // it results in NaN
// ==> "foo" + (+"bar")
// ==> "foo" + NaN
// ==> "fooNaN"

console.log({} + {}); // "[object Object][object Object]"
// curly brace {} represent empty object 
  // and converted to "[object Object]"
// ==> "[object Object]" + "[object Object]"
// ==> "[object Object] [object Object]"

console.log({} + []); // "[object Object]"
// curly brace {} represent empty object 
  // and converted to "[object Object]" and 
  // empty array [] converted to empty string ""
// ==> "[object Object]" + ""
// ==> "[object Object]"

console.log([] + []); // ""
// empty array [] converted to empty string ""
// ==> "" + ""
// ==> ""

console.log([1] + []); // "1"
// when you use the "+" operator with arrays, 
  // it performs array-to-string conversion
// ==> "1" + ""
// ==> "1"

console.log([1, 2] + []); // "1,2"
// when you use the "+" operator with arrays, 
  // it performs array-to-string conversion
// ==> "1,2" + ""
// ==> "1,2"

console.log(!([1] + [])); // false
// If logical operator (&&, ||, !) used in 
  // implicit coercion, then it will give 
  // output in boolean
// !("1") : "1" is truthy value so !("1") = false
// ==> !("1" + "")
// ==> !("1")
// ==> false


console.log({} + [] + {} + [1]); // "[object Object][object Object]1"
// ==> "[object Object]" + "" + "[object Object]" + "1"
// ==> "[object Object][object Object]1"

console.log(!+[] + [] + ![]); // "truefalse"
// +[]: The + operator is used here as the 
  // unary plus operator, which tries to convert 
  // its operand into a number. The operand [] 
  // represents an empty array, which is coerced 
  // into the number 0. So +[] evaluates to 0.
// !0: As 0 is a falsy value so !0 will be true
// ![]: An empty array is considered a truthy value, 
  // so ![] evaluates to false.
// ==> (!+[]) + [] + (![])
// ==> !0 + [] + false
// ==> true + [] + false
// ==> true + "" + false
// ==> "truefalse"

Enter fullscreen mode Exit fullscreen mode

Subtraction Operator (-) Implicit Type Conversion / Coercion

The - symbol is the subtraction operator in JavaScript. When applied to a string and a number, JavaScript automatically tries to convert the string to a number before performing the subtraction.

console.log("10" - 10); // 0
// ==> 10 - 10
// ==> 0

console.log(10 - "10"); // 0
// ==> 10 - 10
// ==> 0

console.log("2" - 1); // 1
// ==> 2 - 1
// ==> 1
Enter fullscreen mode Exit fullscreen mode

Division Operator (/) Implicit Type Conversion / Coercion

The / symbol is the division operator in JavaScript. When applied to a string and a number, JavaScript automatically tries to convert the string to a number before performing the division.

console.log(12 / 6); // 2
// ==> 2

console.log(12 / "6"); // 2
// ==> 12 / 6
// ==> 2

console.log("12" / "6"); // 2
// ==> 12 / 6
// ==> 2
Enter fullscreen mode Exit fullscreen mode

Multiplication Operator (*) Implicit Type Conversion/ Coercion

The * symbol is the multiplication operator in JavaScript. When applied to a number and a string, JavaScript automatically tries to convert the string to a number before performing the multiplication.

console.log(12 * 6); // 72
// ==> 72

console.log(12 * "6"); // 72
// ==> 12 * 6
// ==> 72

console.log("12" * "6"); // 72
// ==> 12 * 6
// ==> 72
Enter fullscreen mode Exit fullscreen mode

Greater Than Operator (>) Implicit Type Conversion / Coercion

In JavaScript, when comparing values using the Greater Than > operator, both operands are automatically converted to numbers before the comparison is made.

console.log(6 > "5"); // true
// ==> 6 > 5
// ==> true

console.log("6" > "45"); // true
// When comparing characters, JavaScript compares 
  // their leftmost Unicode values (UTF-16).
// The first character of "6" is "6", 
  // and the first character of "45" is "4".
// The Unicode value of "6" is 54 and "4" is 52. 
  // So "6" is greater than "4". 
  // Thats why it evaluates to true
// Unicode table: https://asecuritysite.com/coding/asc2
// ==> "6" > "4"
// ==> 54 > 52 
// ==> true

console.log("6" > "75"); // false
// When comparing characters, JavaScript compares 
  // their leftmost Unicode values (UTF-16).
// The first character of "6" is "6", 
  // and the first character of "75" is "7".
// The Unicode value of "6" is 54 and "7" is 55. 
  // So "7" is greater than "6" 
  // Thats why it evaluates to flase
// Unicode table: https://asecuritysite.com/coding/asc2
// ==> "6" > "7"
// ==> 54 > 55
// ==> flase
Enter fullscreen mode Exit fullscreen mode

Loose Equality Operator (==) Implicit Type Conversion / Coercion

Loose equality operator (==) operator performs type coercion before making the comparison. After the type coercion, the loose equality operator (==) checks only the equality of values and ignores the original types.

console.log("true" == true); // false
// "true" trying to convert it into number. 
  // But as it is not a number so it returns NaN
// true convert it into number 1
// ==> "true" == true
// ==> NaN == 1
// ==> false

console.log(false == "false"); // false
// ==> 0 == NaN
// ==> false

console.log(!!"false" == !!"true"); // true
// ==> !!NaN == !!NaN
// ==> !true == !true
// ==> false == false
// ==> true

console.log(["x"] == "x"); // true
// ==> "x" == "x"
// ==> true

console.log(10 == "10"); // true
// Here string type coerces into number befor comparison.
// Now both values are same. So that it retun true
// ==> 10 == 10
// true

console.log([10] == 10); // true
// First, Array coerces to string
// Then string type coerces into number before comparison.
// Now both values are same. So that it retun true
// ==> "10" == 10
// ==> 10 == 10
// ==> true

console.log([10] == "10"); // true
// First, Array converted to string
// Now both values are same. So that it retun true
// ==> "10" == "10"
// ==> true
Enter fullscreen mode Exit fullscreen mode

Strict Equality Operator (===) Implicit Type Conversion / Coercion

The Strict equality operator (===) operator does not perform type coercion. It performs strict equality comparison so checking both value and type.

console.log(10 === "10"); // false
// The number 10 is a numeric value, 
  // while the string "10" is a string value.
// As type doesn't match thats why they return false

console.log([10] === 10); // false
// The array [10] is an object type, 
  // while the number 10 is a number type.
// As type doesn't match thats why they return false

console.log([10] === "10"); // false
// The array [10] is an object type, 
  // while the string 10 is a string type.
// As type doesn't match thats why they return false
Enter fullscreen mode Exit fullscreen mode

Logical And (&&), Logical OR(||) and Logical NOT (!) Operator Type Conversion / Coercion

When evaluating a logical AND operation, JavaScript follows these rules:

  • If the first operand is truthy (not equal to false, null, undefined, 0, NaN, or an empty string), the second operand is returned.
  • If the first operand is falsy, it is returned without evaluating the second operand.

When evaluating a logical OR operation, JavaScript follows these rules:

  • If the first operand is truthy, it is returned without evaluating the second operand.
  • If the first operand is falsy (equal to false, null, undefined, 0, NaN, or an empty string), the second operand is returned.
// logical operator internally convert to Boolean 
  // but it returns in original value 
// the following expression will returns 
  // number 123, instead of returning true
// 'hello' and 123 are still coerced to boolean 
  // internally to calculate the expression
console.log('hello' && 123); // 123
// In this case, "hello" is a non-empty string, 
  // which is a `truthy` value in JavaScript. 
  // Therefore, the logical AND operation continues 
  // to evaluate the second operand, 123.


console.log("hello" || 123); // "hello"
// In this case, "hello" is a non-empty string, 
  // which is a `truthy` value in JavaScript. 
  // Therefore, the logical OR operation returns 
  //the truthy value of the first operand, 
  // which is "hello"

console.log(![]); // false
// ![] : [] is truthy value so ![] = false

console.log([] == ![]); // true
// The loose equality operator (==) operator 
  // in JavaScript performs type coercion 
  // before making the comparison.
// ==> "" == false
// ==> 0 == 0
// true

console.log([] === ![]); // false
// Strict equality operator does not perform 
// type coercion and check type & value
// ==> [] == false
// ==> false

console.log(!4); // false

console.log(!!4); // true
Enter fullscreen mode Exit fullscreen mode

Implicit Type Conversion / Coercion for Null, Undefined and NaN

  • Null implicit type coercion :
  console.log(null + null); // 0
  // null coerces to O. 
  // ==> 0 + 0
  // ==> 0

  console.log(null + 3); // 3
  // null coerces to O. 
  // ==> 0 + 3
  // ==> 3

  console.log(null - 3); // -3
  // null coerces to O. 
  // ==> 0 -3
  // ==> -3

  console.log("4" + null); // "4null"

  console.log([] + null + 1); // "null1"
  // ==> "" + null + 1
  // ==> "null" + 1
  // ==> "null1"

  console.log(null > 0); // false
  // ==> 0 > 0
  // ==> false

  console.log(null < 3); // 3
  // ==> 0 < 3
  // ==> true

  console.log(null + ""); // "null"
  // ==> null + ""
  // ==> "null"

  console.log(null + "3"); // null3
  // ==> null + "3"
  // ==> "null3"

  console.log(null == null); // true
  // If you compare null with null 
    // or undefined you will get true. 
    // Rest of the case it will return false.

  console.log(null === null); // true

  console.log(null == ""); // false

  console.log(null == 5); // false

  console.log(null === 5); // false

  console.log(null == true); // false

  console.log(null == false); // false

  console.log(null == NaN); // false
Enter fullscreen mode Exit fullscreen mode
  • Undefined implicit type coercion :
  console.log(undefined + undefined); // NaN
  // undefined coerces to NaN
  // ==> NaN + 0
  // ==> NaN

  console.log(undefined + 3); // NaN
  // ==> NaN + 3
  // ==> NaN

  console.log(undefined - 3); // NaN
  // ==> NaN -3
  // ==> NaN

  console.log("4" + undefined); // "4undefined"
  // ==> "4" + undefined
  // ==> "4undefined"

  console.log(undefined > 4); // false
  // When comparing undefined with any 
  // value using a relational operator like >, 
  // JavaScript treats undefined as NaN (Not-a-Number).
  // ==> NaN > 4
  // false

  console.log(undefined == ""); // false
  // If you compare undefined with null 
    // or undefined you will get true. 
    // Rest of the case it will return false.

  console.log(undefined == true); // false

  console.log(undefined == false); // false

  console.log(undefined == undefined); // true

  console.log(undefined === undefined); // true

  console.log(undefined == NaN); // false
Enter fullscreen mode Exit fullscreen mode
  • Null and Undefined type coercion together
  console.log(null + undefined); // NaN
  // null and undefined are not numeric values. 
    // In this case, JavaScript tries to convert them 
    // into numbers
  //  null is coerced into a number, it becomes 0
  // undefined is coerced into a number, 
    // it becomes NaN (Not-a-Number)
  // When we add 0 with NaN, the result is NaN.
  // ==> 0 + NaN
  // ==> NaN

  console.log(null - undefined); // NaN
  // null and undefined are not numeric values. 
    // In this case, JavaScript tries to convert 
    // them into numbers
  //  null is coerced into a number, it becomes 0
  // undefined is coerced into a number, 
    // it becomes NaN (Not-a-Number)
  // When we subtract 0 with NaN, 
    // the result is NaN.
  // ==> 0 - NaN
  // ==> NaN

  console.log(null == undefined); // true
  // If you compare null/undefined with null or 
    //undefined you will get true. 
    // Rest of the case it will return false.

  console.log(null === undefined); // false
  // null is an object type, 
    // while undefined is a undefined type.
  // As type doesn't match thats why they return false
Enter fullscreen mode Exit fullscreen mode
  • NaN implicit type coercion
  console.log(NaN + NaN); // NaN
  // ==> NaN + NaN
  // ==> NaN

  console.log(NaN + 3); // NaN
  // ==> NaN + 3
  // ==> NaN

  console.log(NaN - 3); // NaN
  // ==> NaN - 3
  // ==> NaN

  console.log("4" + NaN); // "4NaN"
  // ==> "4" + NaN
  // ==> "4NaN"

  console.log([] + NaN + 1); // "NaN1"
  // ==> "" + NaN + 1
  // ==> "NaN" + 1
  // ==> "NaN1"

  console.log(NaN > 0); // false
  // Any comparison involving NaN evaluates to false.
  // NaN is not a valid number, 
    // and thus cannot be compared to     
    // any other value, even to itself.

  console.log(NaN < 3); // false

  console.log(NaN + ""); // "NaN"
  // ==> NaN + ""
  // ==> "NaN"

  console.log(NaN + "3"); // "NaN3"
  // ==> NaN + "3"
  // ==> "NaN3"

  console.log(NaN == NaN); // false

  console.log(NaN === NaN); // false

  console.log(NaN == ""); // false

  console.log(NaN == true); // false

  console.log(NaN == false); // false

  console.log(null == NaN); // false
Enter fullscreen mode Exit fullscreen mode

Explicit Type Coercion

We know that, Whether it is implicit or explicit type coercion, JavaScript can only convert/coerces to the string, number, and Boolean primitive types. There’s no way in JavaScript to coerce/convert a value type to an object or function.

Explicit String Conversion / Coercion

Explicitly we can convert anything to a string with JavaScript String() method.

console.log(String(43)); // "43"
console.log(String(-43.3)); // "43.3"
console.log(String(null)); // "null"
console.log(String(undefined)); // "undefined"
console.log(String(NaN)); // NaN
console.log(String(true)); // "true"
console.log(String(false)); // "false"
console.log(String(Symbol("my symbol"))); // "Symbol(my symbol)"
Enter fullscreen mode Exit fullscreen mode

Explicit Boolean Conversion / Coercion

Explicitly we can convert anything to a boolean with JavaScript Boolean() method.

We know that a boolean only return true or false. Boolean that only returns falsy values is the following:

console.log(Boolean("")); // false
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(false)); // false
Enter fullscreen mode Exit fullscreen mode

Anything except the above list will return true. The following list will return true.

console.log(Boolean({})); // true
console.log(Boolean([])); // true
console.log(Boolean(Symbol())); // true
console.log(!!Symbol()); // true
console.log(Boolean(function () {})); // true
Enter fullscreen mode Exit fullscreen mode

Explicit Number Conversion / Coercion

Explicitly we can convert anything to a Number or NaN (not-a-number) with JavaScript Number() method.

console.log(Number(123)); // 123
console.log(Number(" 12s ")); // NaN
console.log(Number(" 12 ")); // 12
console.log(Number("-12.34")); // -12.34
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(NaN); // NaN
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number("\\n")); // NaN
Enter fullscreen mode Exit fullscreen mode

References

Thanks for reading ✨!

Connect with me on LinkedIn

Don't forget to share your thoughts in the comment section.

Top comments (0)