Introduction

Probably the most confusing part of the JavaScript is how it works with types. A lot of weirdness can be achieved thanks to JavaScript being flexible and forgiving language with a rich history. You've likely seen fun things like that:



( NaN + Object ()[ " to " + String [ " name " ]][ " call " ]())[ 11 ] // Produces letter "U" 😮

The example above is too extravagated, but in general good developers should understand all the lowdowns of the programming language they are using.

Let's clear all the misconceptions about how and when Javascript converts types.

What types are in JavaScript?

Values in JavaScript are one of the next types:



// We can use typeof function to get the type of the value typeof undefined // "undefined" typeof 42 // "number" typeof " hello " // "string" typeof true // "boolean" typeof { name : ' Jhon ' } // "object" typeof alert // "function" typeof Symbol ( " id " ) // "symbol" typeof null // "object"

This should be pretty self explanatory if you worked with JavaScript already.

The null value of course is not an object though. Its type is "null" . Yet for the historical reasons typeof function returns "object" for the null value.

As JavaScript is a language with a weak typing so it will try to do implicit conversions between the types when it happens. But, implicit is a dangerous word to use in a JavaScript world!

What is a type conversion?

When operand or a function parameter doesn't have expected type...



3 > " 3 " // Expects number, given string 3 + true // Expects number, given boolean alert ( 3 ) // Expects string, given number alert ({ name : ' John ' }) // Expects string, given object

Javascript converts the value to the expected type following specific rules.

Let's examine each of the most possible of them that you can meet in the code:

String type conversion

String type conversion applies when the given value is expected to be a string. The most basic example is the alert function:



alert ( 3 ) // 3 becomes "3" alert ( true ) // true becomes "true" alert ( null ) // null becomes "null"

As you can see, string conversion happens as you would expect in obvious way.

Number type conversion

Number type conversion can be met in the math expressions and comparisons. Here is where usually a lot of confusion comes from.



2 * " 3 " // 6 6 / " 2 " // 3 3 - " 1 " // 2 3 + " 3 " // "33" 🤬

Excuse me? Yes! The + operator actually works a bit different. If one of the operands is a string, then all other operands are converted to string too and it works like string concatenation, not like the math expression:



// One of the operands is string "2" // JavaScript will convert every other operand to string too 1 + " 2 " + true // The result is "12true"

Other that that, the number conversion follows these rules:



parseInt ( true ) // 1 parseInt ( false ) // 0 parseInt ( null ) // 0 parseInt ( undefined ) // NaN parseInt ( " 32 " ) // 32. Whitespaces from the start and end are removed parseInt ( " " ) // 0. If the remaining string is empty, the result is 0 parseInt ( " hi " ) // NaN

That's it. No ✨ magic, only strict rules!

Boolean type conversion

This type conversion happens in the logical operations. It follows strict rules too yet they are mostly obvious:

0 , NaN , undefined , null , "" are converting to false

, , , , are converting to everything else, including objects, to true

if ( " hello " ) // true if ( 0 ) // false if ({}) // true

Type conversions for objects

What JavaScript is going to do if it needs to convert an object to string or number? Let's see:



parseInt ({}) // NaN (converted to number) alert ({}) // "[object Object]" (converted to string) alert ([]) // ""

These are default converted values. You rarely would want to convert objects into primitives... Still, if your code needs a more meaningful conversion you would need to know how to set the conversion rules explicitly.

When converting the object type (not array), JavaScript tries to find and call three object methods:

Call obj[Symbol.toPrimitive](hint) – the method with the symbolic key Symbol.toPrimitive . Otherwise if type of hint is "string" call obj.toString() and obj.valueOf() , whatever exists. Otherwise if type of hint is "number" or "default" call obj.valueOf() and obj.toString() , whatever exists.

The hint is a type of the primitive the object is going to be converted to.

As you can see, you will need to explicitly set Symbol.toPrimitive property for your objects in case you need meaningful visualisation of your object.

Let's create an object and set Symbol.toPrimitive property.



const obj = { name : " Default conversion " } const country = { name : " Estonia " , population : 1291170 , [ Symbol . toPrimitive ]( hint ) { // For string conversion if ( hint == " string " ) { return `Country: ${ this . name } , population: ${ this . population } ` } // Otherwise number conversion return this . population } } alert ( obj ) // "[object Object]" alert ( country ) // "Country: Estonia, population: 1291170" alert ( country + 1 ) // 1291171

Comparison and type conversion

There is two specific comparison rules.

When doing a non-strict comparison Javascript converts operands to numbers if operands have different type:

0 == " 0 " // true. String is converting to a number 0 === " 0 " // false. Strict comparison compares types too! " 0 " != "" // true. There isn't type conversion

null == undefined ! There isn't any type conversion here and these values have different type! Yet in non-strict comparison undefined equals null and undefined by design:

null == undefined // true. God bless JavaScript ❤️

Conclusion

Here we described main rules and approach in which JavaScript makes types conversions. If you carefully observe all these rules you will find that they are basically obvious in most cases. Anyway, in the real production code I would encourage you to avoid implicit type conversions and weird comparisons:

For example, values received from user input will be in the string type. Convert them to number explicitly before using it further:

// ... imagine we handled user input event const money = parseInt ( event . target . value ); alert ( typeof input == " number " ); // true. Now we can safely use money as a number

Concatenate string using template literals instead + operator:

// Can be confusing to read because the result can vary depending on operands types const result = one + two // Explicitly concatenated string const text = ` ${ one }${ two } `

Use strict comparison for comparing values with different types to avoid implicit conversion to number:

const something = 0 ; alert ( something == false ) // true alert ( something === false ) // false

That's it! I hope you found this little guide helpful and now you can better understand types and implicit conversions in JavaScript:



{} + {} // NaN, because object is converting to NaN [] + [] // "", because array is converting to "" 0 == " 0 " // true, because "0" is converting to 0 0 == "" // true, because empty string is converting to 0 "" != " 0 " // true, because operands are the same type (string) and no conversion happens

Happy coding! ❤️