Tuesday, July 16, 2024

Understanding Primitive Type Coercion in JavaScript

JavaScript Tutorials

All programming languages, including JavaScript (JS), have built-in data types; these include strings, numbers, Dates, Arrays, and so forth. What makes JS special is that it is loosely typed. Hence, variables are declared without a type, which allows them to be re-assigned values of a different type at any time. This feature makes the language more dynamic, but also leads to more bugs than probably all other features combined! It is such a problem, in fact, that TypeScript was created to bring strong typing to the JavaScript language.

Not that JS’s automatic type coercion is all bad – it is part of what makes JavaScript one of the easiest programming languages for beginners to learn, and undoubtedly played a substantial role in JS’s longevity and popularity. For more experienced developers, the path to less frustration is to take some time to learn the ECMAScript Language Specification Standard and become more adept at navigating type coercion’s many quirks. Consider this web development tutorial as a starting point on that journey, as we cover how JavaScript converts one type into another based on how variables interacts with each other in code.

You can learn more about ECMAScript in our tutorial: Asynchronous Programming in ECMAScript.

What Are JavaScript’s Primitive Types?

Before we can talk about type coercion, we should establish what JavaScript’s types are, since you will not see them when you declare variables. JavaScript has seven primitive types:

  • string
  • number
  • Boolean
  • undefined
  • null
  • Symbol
  • BigInt

What all of the above types have in common is that thy are not objects, and, as such, have no methods or properties, unlike say Arrays or Dates.

You may also want to check out our guide to Working with CSS Variables.

How to Verify a Variable’s Type in JavaScript

Web developers can get a variable’s type (at that moment in time), using the typeof operator:

console.log(typeof 42);
// expected output: "number"

console.log(typeof 'blubber');
// expected output: "string"

console.log(typeof true);
// expected output: "boolean"

console.log(typeof undeclaredVariable);
// expected output: "undefined"

Number and BigInt have a related value NaN. Short for “Not a Number”, NaN is typically encountered when the result of an arithmetic operation cannot be expressed as a number. It is also the only value in JavaScript that is not equal to itself!

// outputs NaN

Implicit vs. Explicit Coercion in JavaScript

Amazingly, all type coercion issues in JavaScript are caused by the string, number, and boolean primitive types (there is no way in JavaScript to coerce a primitive type to object or function)! Implicit type coercion happens when we mix different types within the same operation or series of operations.

Coercing to Boolean in JavaScript

The weird thing about booleans is that all primitive values also have an inherent boolean value, which makes them either “truthy” or “falsy”. Some of the rules that determine how non-boolean values are coerced into true or false values are not intuitive, so it is worth going over those now.

The following values are always falsy:

  • false
  • 0 (zero)
  • -0 (minus zero)
  • 0n (BigInt zero)
  • an empty string, e.g. ”, “”, “
  • null
  • undefined
  • NaN

Everything else is truthy. That includes:

  • a non-empty string, e.g. “test string”, ‘0’, ‘false’
  • any non-zero number, e.g. 1, -1, 2112

That is why programmers can test for truthiness in an if statement:

var widget = 'bolt';

//later in the code
if (widget) {
  // do something

As long as the widget variable contains a non-empty string, the if block will get executed.

Rather than let JS coerce expressions into a boolean result, it is perfectly acceptable to do it yourself using the Boolean() function:

var widget = 'bolt';
var isSoldOut = false;

//later in the code
if (widget !== '' && !Boolean(isSoldOut)) {
  // do something

Numeric Coercion in JavaScript

If you try to compare a variable of a different type to a number, JS will helpfully coerce it to a number, in order to perform an apple to apple comparison. When a type can not be coerced to a number, the returned result is NaN. For example, an empty string will be converted to a zero (0). Some developers have been critical of this behavior because they do not agree that an empty string should be considered to be a valid number, some have even gone so far as to state that “empty strings becoming 0 is the root of all coercion evil” (Kyle Simpson, the creator of the You Don’t Know JS book series).

Not that implicit type coercion is all bad. It does allow us to do fancy stuff like this:

// Adds 1 to the currentIndex if the userId is 99.
var index = currentIndex + (userId == 99);
var info = userData[index];

Just to be safe, you could make sure that index contains a valid number by using the Number() function:

// Adds 1 to the currentIndex if the userId is 99.
var index = currentIndex + (userId == 99);
if ( !isNaN(Number(index)) ) {
   var info = userData[index];

Just don’t use typeof, because it will return “number” even for NaN!

Read: Best Online Courses to Learn HTML

JavaScript String Conversion

Issues with implicit coercion to the string type can arise mixing types such as numbers and strings in the same expression. For example, does 10 + “10” evaluate to the number 20 or the string “1010”? (It is the latter.) Even if you know the answer, maybe the next developer won’t, so why take chances?

var val1 = 10;
var val2 = "10";
var stringResult = String(val1) + String(val2);
var numResult = Number(val1) + Number(val2);

Shortcuts to JavaScript String Conversion

Experienced JavaScript developers often employ Unary operators to trigger coercion of a variable into the desired type. For instance, the “+” operator will cause a variable to be coerced into a number. Hence, +val1 + +val2 is equivalent to the Number(val1) + Number(val2) statement that we saw above.

Likewise, the bang “!” operator will force the coercion of a variable into a boolean value. You will often see it used in if statements like if (!val1) { for truthiness and if (!!val1) { for falsiness.

There is no Unary operator for strings, but some developers force coercion to a string by concatenating an empty string to a variable as in val1 + ”. I’m personally not a fan and prefer to explicitly convert the variable in question into a string using the String() function:

var stringVal = String(val1);

Final Thoughts on JavaScript Type Coercion

JavaScript’s implicit coercion is a double edged sword. On the one hand, it makes the language easy to pick up by novice coders. On the other, it can lead to untold hardships for more experienced developers who have to deal with all of the bugs it engenders. If you take one thing away from this tutorial, it’s that you should not rely on implicit coercion to compare primitive type variables and instead explicitly convert them yourself using functions such as String(), Number(), and Boolean().

Read more JavaScript web development tutorials.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles