The WHY behind the WAT: An explanation of JavaScript’s weird type system
Abhinav Suri

JavaScript is a loosely typed language, meaning you don’t have to specify what type of information will be stored in a variable in advance. JavaScript automatically types a variable based on what kind of information you assign to it (e.g., that '' or " " to indicate string values). Many other languages, like Java, require you to declare a variable’s type, such as int, float, boolean, or String.

This is both a blessing and a curse.

While JavaScript’s type system gives you a lot of flexibility, it lacks the capability of a strongly typed system to yell at you when you are trying to add an int to an object, which protects you from spending hours debugging a type error.

Here are some useful tips to help you navigate JavaScript’s weird type system.

#1 typeof

whenever a variable’s type is in doubt, you can employ the typeof operator:

typeof 1 //> “number”
typeof “1” //> “string”
typeof [1,2,3] //> “object”
typeof {name: “john”, country: “usa”} //> “object”
typeof true //> “boolean”
typeof (1 === 1) //> “boolean”
typeof undefined //> “undefined”
typeof null //> “object”
const f = () => 2
typeof f //> “function”

Key Takeaway: When the type is in doubt, use typeof.

#2 Double Equals Versus Triple Equals

The === mean “equality without type coercion”. Using the triple equals, the values must be equal in type as well.

1 == “1” //> true
1 === “1” //> false
null == undefined //> true
null === undefined //> false
‘0’ == false //> true
‘0’ === false //> false
0 == false //> true
0 === false //> false, because they are of a different type

Note, you can use !== for checking inequality with type coercion:

1 != "1" //> false
1 !== "1" //> true

Key Takeaway: Always use === since that is a more thorough check and help you avoid nasty bugs.

#3 Checking for Falsiness

Using the ! operator (called the “bang” operator) to check for falsiness, we notice the following:

!null //> true
!undefined //> true
!0 //> true
!"" //> true
!false //> true
![] //> false
!42 //> false
!"hello world" //> false

null, undefined, 0, “”, and false all returned true when we applied the ! operator. When we applied the ! operator on things that do exist, such as the number 42 or the string “hello world”, we get false.

This shows that null, undefined, 0, “”, and false all represent non-existence or falsy values, but not in the same way. 0 is a number and represents the non-existence of quantity. “” is a string and represents the non-existence of substance in the string. And lastly, false is a boolean and represents the lack of true. This can be verified with a simple typeof:

typeof 0 //> "number"
typeof "" //> "string"
typeof false //> "boolean"

undefined and null are more tricky. As shown by the example below, they are different types, have the same value, but fails the === comparison:

typeof undefined //> “undefined”
typeof null //> “object”
undefined == null //> true
undefined === null //> false

Because null is an object, we can add a number to it. For undefinedhowever, adding a number to it gives you NaN.

null + //> 1
undefined + 1 //> NaN

Adding a number to a null seems like it could be a nice shortcut sometimes, but don’t do it!

Although null is an object, you get a number when you add a number to it. However, when you add other things to it, it gives you non-sensical strings:

null + [1,2,3]//> "null1,2,3"
null + ["hello", "world"] //> "nullhello,world"
null+ {0: "hello", 1: "world"} //> "null[object Object]"

Key Takeaways:

  • you need to be careful when you check for truthiness. Use === and check of all types of potential falsy values, e.g., if(foo === undefined || foo === null) ... — which can get quite tedious.
  • Best practice is to check for falsiness instead by using the ! operator to check for all of the falsy values, i.e., null, undefined, 0, “”, and false, in one action.
  • Don’t add things to null.