DEV Community

LV 🏳️‍🌈
LV 🏳️‍🌈

Posted on

Coercion Between Primitives and Objects in JavaScript

Every JavaScript developer has read at least one article that describes the unexpected values you get when you perform operations with mismatched types. This is not one of those posts. So relax, I won’t try to trip you up with type coercion examples.

The idea for this article was born while I was working with Flow, a type checker for JavaScript. While declaring types, I accidentally gave an argument type Boolean and not boolean. I realized there was a casual subtly to my mistake so I wanted to talk about why these two things aren’t the same.

The difference between String and string

There are six primitive types in JavaScript: boolean, string, number, null, undefined, and symbol. Right now we’ll focus on the first three. These three have wrapper objects called Boolean, String, and Number. You’ve probably used these special wrapper objects when doing an explicit type conversion, e.g.:

    let example = 6;
    7 === 1 + Number(example)  // true

Since JavaScript is loosely typed, you use implicit type coercion between these types all the time, e.g:

    let example = This is a string;
    example.length  // 16

Here, the JavaScript interpreter sees that you are trying to use a primitive as an object by accessing a property. Since primitives don’t have properties, the interpreter wraps the string primitive in an object by calling String(example) in the background. This allows you to use the primitive like an object.

Boolean vs. boolean and why it matters

For the most part, we can use primitives and wrapper types the same way with no issue. But here’s a particular case where that’s not true.

    let example = new Boolean(false);
    if (example) {
        console.log(Cats are the best);
    } else {
        console.log(Dogs are the best);

Go ahead and try this example in your console right now.

You might be surprised to see that it prints out ‘Cats are the best’! Since all objects are truthy in JavaScript, example evaluates to true, which can be unintuitive.

Now you know one the reasons why Flow doesn’t let you use primitive and wrapper types interchangeably. I suggest playing around with this over at Flow's playground.

Discussion (0)