Back to Blog

Understanding Typeof in JavaScript

Chidume Nnamdi


As the name implies, the typeof keyword is used to determine the types of data. This is one of the most common JS keywords found in JS apps. Knowing the type of data you are working on is often found crucial. In this post, we will look into the typeof keyword in JS.


typeof usage


typeof data


The data is the variable we want to get the data type. Notice there is no parenthesis just the typeof keyword followed by a space and the data.


// typeof.js

let num = 90l(typeof num)

num is a number so typeof will return a number string:

number


Let’s see other examples:


// typeof.js
const l = console.log
let str = "str"
let num = 90
let undef = undefined
let nul = null
let obj = { d: 90 }
let arr = [90]
function func() {}
let sym = Symbol("sym")
let bool = true
function showtype(data) {
l(typeof data)
}
showtype(str)
showtype(num)
showtype(undef)
showtype(nul)
showtype(obj)
showtype(arr)
showtype(func)
showtype(bool)
showtype(sym)


Output:

$ node typeof

string

number

undefined

object

object

object

function

boolean

symbol


What it returns


typeof keyword returns one of the following data types:

  • string
  • number
  • undefined
  • object
  • function
  • boolean
  • symbol
  • bigint


string: Anything between “” is a string in JS:


let str = "str"

The variable str is a string data type. So typeof str will return string.

number: This represents numbers 0~9. typeof against a Number type will return “number”.

let num = 90l(typeof num)


Output:

$ node typeofnumber

The NaN also returns number contrary to its meaning NaN => Not a Number

let nan = NaNl(typeof nan)


Output:

$ node typeofnumber

This is very confusing, how can a value that is “Not a Number” eval to a number? To check for NaN, it’s obvious we can’t use the typeof keyword, we will use the isNaN function.


let nan = NaNl(typeof nan)l(isNaN(nan))


Output:

numbertrue



let undefl(undef)let undef1 = undefinedl(undef1)

undefined This is returned when a variable has no value set yet or has an undefined set explicitly.


When typeof is set against an undefined variable it will return “undefined”:

let undefl(under)let undef1 = undefinedl(undef1)l(typeof undef)l(typeof undef1)


Output:

$ node typeofundefinedundefined

This is good, so we can check for undefined values using the typeof keyword.

object: This is a bit tricky. Many variable types return objects.

null, array, object


let nul = nulllet obj = { d: 90 }let arr = [90]l(typeof nul)l(typeof obj)l(typeof arr)


Output:

$ node typeofobjectobjectobject


We can see that all of them return the object as type. With this, we cannot test null and array with the typeof operator.

But, null being an object. That’s mind-boggling. History told us this was an unfixed bug in Js and it has haunted us p to this day. Fixing the bug now, we crash billions of JS codebase and apps. So we have to live with it.

To check for null, we will use either the loose equality or strict equality, in both, the == resolves to true to itself:


let nul = nulll(nul == null)l(nul === null)


Output:

truetrue


function: functions resolve to “function” under typeof. Pretty easy. regular functions, expression or arrow functions, and IIFEs all resolve to “function”.

function func() {}const arrFunc = () => {}l(typeof func)l(typeof arrFunc)


Output:

$ node typeoffunctionfunction


boolean: Boolean has two values true or false. These return the boolean type.

let bool = true(bool)


Output:

$ node typeofboolean


So we see its quite easy to check for booleans. Boolean shave truthy and falsy values. All values in JS are truthy except the falsy ones. falsy values are:

  • 0
  • “” (Empty string)
  • NaN
  • false
  • null
  • undefined


symbol: This is used to creating non-clashing names in JS. They are mostly used in creating keys in objects. These return “symbol” string.


let sym = Symbol("sym")l(typeof sym)


Output:

$ node typeofsymbol


bigint

BigInt is a built-in object that represents numbers between range 2⁵³ — 1. To create a bigint variable type, we append n to the end of an integer literal. bigint is returned when a variable of BigInt is used against typeof:


let bigint = 90nl(typeof bigint)


Output:

$ node typeofbigint


typeof and wrapper functions


Using new Boolean, new String, etc breaks the typeof result on them.

If I do this:


let bool = new Boolean(true)


It will no longer return true, it will return an object when its type is checked with typeof


let bool = new Boolean(true)l(typeof bool)


Output:

$ node typeofobject

These wrapper functions break the data type. Whenever we use wrapper functions on primitives, JS coerces them to objects. We know primitive types do not have properties, they are standalone.

let str = "str"let num = 90

But if we do this to str:

str.length

We are accessing a property in the primitive, it shouldn’t be so but yet we have a result:

3


JS coerces str primitive to object then have the length property retrieved. On returning the result the str becomes primitive again.

In str.length property, JS did this:


l(new String("str").length)


It wrapped the str in new String() before accessing the length property.


typeof and objects


As we saw above Arrays, null, object, NaN all return “object”. Others concepts, RegExp, Date all return “object”. So we cannot test for Array or any of them using typeof.

Array has Array#isArray(...) that correctly determines a data is an Array.

To check for null you can either


isNull === null

or

!isNull && typeof isNull == "object"


For NaN use isNaN or Number#isNaN API.

For Date, use duck typing:

typeof date.getMonth === "function"


or you can use instanceof but it will return for invalid dates too.


Conclusion


typeof is both a powerful and indeterminate tool in type checking. It kind of has a buggy behavior when dealing with null, NaN, object, Array, Object, etc types. However, it is useful for some primitive types: number, bigint, symbol, undefined, string, boolean.

If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email or DM me.

Thanks!


More from the Blog

Native Lazy Loading 💤 is coming to our browser

The prospect of lazy-loading is to minimize the load of bundles that are loaded in the initial page fetch. With lazy-loading, these tags’ contents are not loaded until they are scrolled up to the viewport of the browser. This is famously used in Medium.

Read Story

Native FileSystem API is coming to our browser 😍

Accessing the filesystem is a common feature of apps, but coming to the browser it’s an all-out battle with the filesystem. But Chrome is changing all that with the coming of the Native Filesystem API. 

Read Story

Become a JavaScript-on-Mobile Pro with PWA’s

Responsive design took over the internet back in 2012, however the tech had been brewing since 2007, when Steve Jobs introduced the idea of web-apps to the world at the launch of the first iPhone.

Read Story

Stay in the Loop.

Gitstart runs a monthly email newsletter for developers, engineering leaders and CEOs, covering latest tips and trends.
We will never share your email address with third parties.