The typeof statement is useful in JavaScript for data validation and type checking, but it has some odd features to be aware of.

There are two instances when typeof returns "object" in an unexpected way, and this makes type checking a little unusual.

What Is the Typeof Statement in JavaScript?

Typeof is a statement that’s used in JavaScript to check the type variable in your code. It can return one of JavaScript’s eight data types, and it’s especially useful for returning most of the primitive types in JavaScript, including undefined, string and number. 

Both typeof null and typeof an array return "object" in a potentially misleading way, as null is a primitive type (not an object), and arrays are a special, built-in type of object in JavaScript.

In this article, I examine every possible result of typeof in JavaScript.

 

Data Types

While there are only eight data types (seven primitives and objects) in JavaScript, typeof will actually return one of nine options:

  1. undefined
  2. object (meaning null)
  3. boolean
  4. number
  5. bigint
  6. string
  7. symbol
  8. function
  9. object (meaning any object, including arrays)

These correspond to the JavaScript data types, with the exception that the typeof null is also "object" due to a long-standing bug.

Next, I explain when to expect each response from typeof in detail.

More on JavaScript: What Are JavaScript Design Patterns?

 

Undefined

An undefined value in JavaScript is pretty common. It means a variable name has been reserved, but no value has been assigned to that reference yet. It’s not defined yet, so we call it undefined.

The value undefined is a primitive type in JavaScript, and undeclared variables are also considered to be undefined.

Referencing undeclared variables usually results in a ReferenceError, except when using the typeof keyword.

The typeof undefined is the string "undefined" — and undefined is a falsy value that is loosely equal to null but not to other falsy values.

// The value undefined is loosely equals to null but not other falsy values:
console.log(undefined === undefined) // true
console.log(undefined === null) // false
console.log(undefined == null) // true
console.log(Boolean(undefined)) // false
console.log(undefined == false) // false

// The typeof keyword returns "undefined" for the value undefined:
console.log(typeof undefined) // undefined

// A declared variable that has not been assigned a value is undefined by default:
let undefinedVariable
console.log(undefinedVariable) // undefined
console.log(typeof undefinedVariable) // undefined

// The typeof an undeclared variable is undefined, making it a safe way to check if a variable has been declared:
console.log(typeof undeclaredVariable)

// Referencing an undeclared variable without typeof will throw a ReferenceError:
try { undeclaredVariable } catch(e) { console.log(e) } // ReferenceError: undeclaredVariable is not defined

If typeof says a value is "undefined", then it’s a safe bet to assume that value is actually undefined, meaning it was not declared, declared but never assigned a value or declared and assigned the value of undefined.

 

Null Object

For historical reasons, the typeofnull in JavaScript is "object". This is a bug that is expected to never be fixed in JavaScript.

That means that checking for null cannot be performed using typeof.

However, null checking is pretty easy using the strict equality operator (===) to check that the value is indeed null, as in maybeNull===null.

 

Useful Things to Know About Null

  1. The value null is falsy (evaluates to false in a conditional).
  2. The values null and undefined are only loosely equal to each other.
  3. Neither null nor undefined are equal to other falsy values.

This means that checking for null using the loose equality (==) operator will capture both null and undefined values, which can be useful:

console.log(null) // null
console.log(typeof null) // "object"

console.log(null === null) // true
console.log(null === undefined) // false
console.log(null == undefined) // true
console.log(null == false) // false
console.log(Boolean(null)) // false

// Alternatively, null is the only falsy object
console.log(!null && typeof null === "object") // true
isNull = (value) => !value && typeof value === "object"
console.log(isNull(null)) // true

Often, an undefined value means the same thing as a null value — the absence of a value — so, using == is recommended to check for null.

On the other hand, checking for null can be performed easily with the strict equality === operator.

Or one can check by knowing that since the empty object is truthy (evaluates to Boolean true in a conditional), null is the only falsy object.

 

Boolean

Checking for Boolean values is easy. They are going to be either true or false, and the typeof a boolean returns "boolean":

console.log(typeof true) // boolean
console.log(typeof false) // boolean

// The Boolean() wrapper will convert truthy and falsy values:
console.log(typeof Boolean(37)) // boolean
console.log(typeof Boolean(0)) // boolean

// Two exclamation points !! (the logical NOT) operator are equivalent to Boolean()
console.log(typeof !!(37)) === // boolean
console.log(typeof !!(0)) === // boolean

// Conditionals will coerce values to boolean in the same way:
37 ? console.log("truthy") : console.log("falsy") // truthy
0 ? console.log("truthy") : console.log("falsy") // falsy

Note that JavaScript will coerce any value to true or false by using the Boolean() wrapper function, which puts two exclamation points (the logical NOT — !) in front of the expression. Or it’ll put the statement inside of a conditional, such as an if statement, question mark ? operator, or loop.

The values that evaluate to false are called the falsy values, and everything else in JavaScript evaluates to true and is a truthy value.

The falsy values in JavaScript are false, 0, 0n, null, undefined, NaN and the empty string “”. Everything else is truthy.

 

Number

Checking for a number in JavaScript works as expected, with typeof returning "number":

console.log(typeof 37) // "number"
console.log(typeof 2.71828) // "number"
console.log(typeof Math.E) // "number"
console.log(typeof Infinity) // "number"

// The typeof NaN is "number" even though NaN means "Not-A-Number":
console.log(typeof NaN) // "number"

// Calling Number explicitly is one way to parse a number:
console.log(typeof Number(`1`)) // "number"

// The parseInt and parseFloat functions are other ways to parse:
console.log(typeof parseInt(`100`)) // "number"
console.log(typeof parseFloat(`100.01`)) // "number" 

// Parse failures lead to NaN, and NaN poisons other math:
console.log(typeof (2 * parseInt(`invalid`))) // "number"

Note that this means that checking for NaN requires checking for self-equality because NaN is the only value in JavaScript that doesn’t equal itself:

const mightBeNaN = NaN // NaN means "Not-a-Number"

// Anything compares false when compared to NaN:
console.log(37 === NaN) // false
console.log(mightBeNaN === NaN) // false

// NaN is the only value that does not equal itself:
console.log(mightBeNaN !== mightBeNaN) // true

// Creating an invalid Date results in the value NaN:
console.log(new Date(`invalid`) !== new Date(`invalid`)) // true

// For improved code readability, some developers prefer Number.isNan():
console.log(Number.isNan(mightBeNaN)) // true


 

BigInt

Checking for the primitive type BigInt works as expected; typeof for supported browsers will return "bigint":

console.log(typeof 37n) // bigint

“BigInt is a built-in object that provides a way to represent whole numbers larger than 253 - 1, which is the largest number JavaScript can reliably represent with the Number primitive. BigInt can be used for arbitrarily large integers,” according to the MDN web documentation.

Officially, BigInt was added to modern JavaScript as part of ES11 (ECMAScript 2020), and it is supported by Chrome, and thus by Node.js, Firefox and Edge.

 

String

As one might hope, checking for a string in JavaScript is pretty straight-forward. typeof works exactly as expected, returning "string":

console.log(typeof '37') // string
console.log(typeof "37") // string
console.log(typeof `37`) // string

// Note that typeof always returns a string:
console.log(typeof (typeof 37)) // string

// The String() wrapper function converts anything into a string:
console.log(String(37))

It sure is nice when things work like they should when programming.

 

Symbol

The primitive data type symbol is a unique identifier, useful for creating keys on objects in JavaScript.

“A symbol value may be used as an identifier for object properties; this is the data type’s only purpose,” according to MDN web docs.

As one would expect, the typeof Symbol() is indeed "symbol":

console.log(typeof Symbol()) // symbol
console.log(typeof Symbol(37)) // symbol
console.log(typeof Symbol.iterator) // symbol

const symbolUno = Symbol()
const symbolDos = Symbol(37)
const symbolTres = Symbol("37")

console.log(typeof symbolUno) // symbol
console.log(String(symbolTres)) // Symbol(37)

//  Every symbol value returned from Symbol() is unique:
console.log(Symbol() === Symbol()) // false
console.log(Symbol(37) === Symbol(37)) // false
console.log(Symbol("37") === Symbol("37")) // false

 

Function

Functions are easily checked for using the typeof keyword, which works entirely as expected by returning "function":

console.log(typeof function myFunction() {}) // function
console.log(typeof class myClass {}) // function
console.log(typeof (() => {})) // function

// This includes built-in functions, for example Number.isNaN():
console.log(typeof Number.isNaN) // "function"

// But not properties, of course:
console.log(typeof "".length) // "number"

// And calling a function will check the typeof the return value:
console.log(typeof Number.isNaN()) // "boolean"
console.log(typeof Number.isNaN(37)) // "boolean"

 

Object (Meaning Object or Array)

As long as the value in question is not null, typeof returning "object" means that the JavaScript value is a JavaScript object.

One type of object that is built into JavaScript is the array, and the typeof of an array is "object": typeof [] === `object` // true.

ECMAScript 5 introduced an Array.isArray() method to check for an array, since typeof will not be able to tell arrays from other objects.

The JavaScript prototypes Date and RegExp are two other types of built-in objects where typeof returns “object.” Thus, dates and regular expressions need more differentiation than just using the typeof keyword.

Here’s how to check the type of objects and arrays:

const helloWorldObject = { hello: "world" }
console.log(typeof helloWorldObject) // 'object'
// use Array.isArray or Object.prototype.toString.call
// to differentiate regular objects from arrays
const fibonacciArray = [1, 1, 2, 3, 5, 8]
console.log(typeof fibonacciArray) // 'object'
console.log(Array.isArray(helloWorldObject)) // false
console.log(Array.isArray(fibonacciArray)) // true

// There is another helper function, though it is a bit long:
console.log(Object.prototype.toString.call(helloWorldObject)) // [object Object]
console.log(Object.prototype.toString.call(fibonacciArray)) // [object Array]

// Regular expression have their own native object, RegExp
const myRegExp = /search/
console.log(typeof myRegExp) // 'object'
console.log(myRegExp instanceof RegExp) // true
console.log(Object.prototype.toString.call(myRegExp)) // [object RegExp]

// The Date native object is built-in to JavaScript
const emptyDate = new Date()
const invalidDate = new Date("fail")
console.log(typeof emptyDate) // 'object'
console.log(typeof invalidDate) // 'object'
// Checking for a date is a little trickier
console.log(emptyDate instanceof Date)
console.log(invalidDate instanceof Date)
console.log(Object.prototype.toString.call(invalidDate)) // [object Date]
// Reliable date checking requires a NaN check by checking for NaN:
console.log(invalidDate instanceof Date && !Number.isNaN(invalidDate.valueOf())) // true

The verbose JavaScript statement Object.prototype.toString.call() can differentiate between generic objects, arrays and other objects because it returns a string that specifies the object type in more detail than typeof.

Similarly, the helper method Array.isArray() or the keyword instanceof can be used to check for arrays or any type of object, respectively.

 

Typeof and Object Wrappers Explained

The object wrappers for Boolean, number and string will break typeof and result in "object" instead of "boolean", "number", or "string".

// "The following are confusing, dangerous, and wasteful. Avoid them." -MDN Docs
typeof new Boolean(false) === 'object'; // true
typeof new Number(37) === 'object'; // true 
typeof new String(`Hello World!`) === 'object'; // true

Why do these object wrappers exist if they should not be called explicitly?

Basically, calling a string property like "".length results in JavaScript making a wrapper object and interpreting the code this way:

"".length === String("").length // true

Since that happens automatically, there is no need to create an explicit wrapper object, as it will only break typeof, as shown above.

 

Why You Shouldn’t Use Wrapper Objects

Similarly, wrapper objects change the function of the == and === equality operators in JavaScript.

And the behavior only actually changes when the new keyword is used with the object wrapper call, as is shown in the following example:

const primitiveString = `Hello world!` // primitive type string
const wrappedString = new String(`Hello world!`) // wrapper object

console.log(typeof primitiveString) // "string"
console.log(typeof wrappedString) // "object"

console.log(primitiveString == wrappedString)  // true
console.log(primitiveString === wrappedString) // false

const almostWrappedString = String(`Hello world!`) // wrapper called without new
console.log(typeof almostWrappedString) // "string"
console.log(primitiveString === almostWrappedString) // true

Generally speaking, the string, Boolean and number wrappers will be called automatically and should not be called by JavaScript developers.

 

Typeof and Host Objects in JavaScript

Host objects are implementation-dependent, meaning they are supplied by the local run-time environment.

Put another way, host objects are special objects beyond the standard built-in objects or native objects JavaScript provides.

For example, the window object is supplied by the browser-environment supplies, while a node.js environment supplies other host objects.

This means that the typeof keyword is also implementation-dependent, at least in the case of host objects.

That being said, modern implementations are probably going to return “object” as the typeof host objects. For example:

typeof window // "object"

 

Are Static Types the Future in JavaScript?

Since JavaScript is a dynamically typed language but typeof has its quirks, some developers prefer automatic or static type checking using a language like TypeScript or a static type checker like Flow.

Using TypeScript or Flow definitely has some advantages and can prevent bugs, but at the cost of learning and implementing another tool.

While useful, using either TypeScript or Flow will add a whole new layer of complexity to your JavaScript programming.

For vanilla JavaScript, mastering typeof is all you need in order to check data types like a champion.

An introduction to the typeof operator in JavaScript. | Video: Java Brains

More on JavaScript: Creating an Npm-Only Build Step for JavaScript — the Easy Way

 

Advantages of Typeof in JavaScript

The keyword typeof is useful for type checking in JavaScript, but it has some caveats associated with historical bugs.

Type checking with typeof is especially useful for most of the primitive types in JavaScript, including undefined, string and number.

On the other hand, Array, Date and Regular Expressions are native objects that are not differentiated from each other by typeof. They all return "object" — as does null, unexpectedly in a well-known bug.

In short, typeof is an imperfect but powerful tool to check a value’s type.

Expert Contributors

Built In’s expert contributor network publishes thoughtful, solutions-oriented stories written by innovative tech professionals. It is the tech industry’s definitive destination for sharing compelling, first-person accounts of problem-solving on the road to innovation.

Learn More

Great Companies Need Great People. That's Where We Come In.

Recruit With Us