What exactly is Type Coercion in Javascript?
Let’s start with a short intro to type systems which I think will help you understand the general idea of type coercion.
The type system of a language defines rules that tell us what types of data exist in that language and how they can be combined using different operators. For example, one such rule might specify that the plus (+) operator only acts on numbers. These rules exist primarily to prevent you from shooting yourself in the foot. But what happens when the programmer breaks that rule in the program? There’s nothing preventing the programmer from typing {} + {}
or “hello” + 5
in a program even if the language doesn’t think those expressions make any sense.
What ultimately happens in those situations depends on how strict the language is about its type rules.
A languages type system often holds one of two positions about you breaking its rules:
- Say “Hey, that’s not cool!” and immediately crash your program.
- Say “I can’t do anything with {} … but I can do something with numbers” and attempt to convert {} to a number.
Languages with type systems that take the first position about its rules are colloquially referred to as “strongly typed” languages. They are strict about not letting you break its rules. Those that take the second approach (such as JavaScript) are referred to as “weakly typed” or “loosely typed” languages. Sure, you can break the rules, but don’t be surprised when it converts the type of data you described in your program by force in order to comply with its rules. That behavior is known as … (drum roll) ... type coercion.
Now let's look at some examples in JavaScript. First, let's start with an expression that does not lead to type coercion.
5 + 5
Using the + operator with two numbers which is perfectly valid. The program will treat + to mean “add” and happily add the two numbers. No conversion necessary.
But what about …
[] + 5
Uh oh. In JavaScript, +
can mean add two numbers or concatenate two strings. In this case, we have neither two numbers nor two strings. We only have one number and an object. According to JavaScript's type rules, this makes no logical sense. Since it’s forgiving about you breaking its rules, instead of crashing it tries to make sense of it anyway. So what does JavaScript do? Well, it knows how to concatenate strings, so it converts both [] and 5 into strings and the result is string value “5”.
What’s the deal with the comparison operators ==
and ===
? Why are there two comparison operators?
==
is not immune to JavaScript’s type conversion behavior. Expressions such as 5 == “5”
will evaluate to true because JavaScript will attempt to convert one of them so that it’s comparing the same type of data.
In many cases, that’s not desirable because you probably want to know if some data you’re comparing against is of a different type so that you can decide what to do about it. That’s where the ===
operator comes in. When you use ===
, no type conversion will take place. Therefore, the expression 5 === “5”
will evaluate to false.
In Python if you try to add, say, strings and integers, you get an error:
>>> "hi" + 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
Yet in JavaScript, you don't. The 10
gets converted to a string:
> "hi" + 10
"hi10"
"Type coercion" is just a fancy misnomer for the above. In actuality, neither language has "types" in the sense of Java or C or other languages with static type systems. How the languages treat interactions between the various non-statically-typed values is a matter of choice and convention.
Type coercion means that when the operands of an operator are different types, one of them will be converted to an "equivalent" value of the other operand's type. For instance, if you do:
boolean == integer
the boolean operand will be converted to an integer: false
becomes 0
, true
becomes 1. Then the two values are compared.
However, if you use the non-converting comparison operator ===
, no such conversion occurs. When the operands are of different types, this operator returns false
, and only compares the values when they're of the same type.
Coercion isn't only done by comparison operators, although they're the only ones that have both "strict" and "loose" variants. Most arithmetic operators will automatically converse non-numeric arguments to numbers, e.g. "50" / 5
is treated as 50 / 5
. There are also many built-in functions and methods that require string arguments; if you give them something else, they'll automatically coerce them to strings.
But be careful -- +
is both the arithmetic addition operator and the string concatenation operator -- if you do string + number
, it converts the number to a string and concatenates, rather than converting the string to a number and adding. This is the source of many errors made when performing arithmetic on user input, since input is a string unless you explicitly convert it.
You can find a good explanation of JavaScript's coercion rules in You Don't Know JS and more reference-oriented documentation in MDN.