JavaScript typeof vs instanceof: How to Check Types Correctly

JavaScript gives you two common ways to inspect values: typeof and instanceof. They look similar at first, but they answer different questions, and using the wrong one can lead to confusing bugs in type checks, validation code, and error handling.

Quick answer: Use typeof for primitive values and functions, such as strings, numbers, booleans, and functions. Use instanceof to check whether an object comes from a particular constructor or class through its prototype chain.

Difficulty: Beginner

You'll understand this better if you know: basic JavaScript values, objects, and how functions and classes create instances.

1. What Are typeof and instanceof?

typeof is a unary operator that returns a string describing the general type of a value. instanceof is an operator that checks whether an object was created by a particular constructor function or class, or inherits from it through the prototype chain.

2. Why typeof and instanceof Matter

Type checks are common in input validation, defensive programming, library code, and debugging. If you misunderstand these operators, you may accept the wrong values, reject valid ones, or get misleading results from expressions that seem obvious.

For example, code that checks for an array with typeof value === "object" is too broad, because arrays, dates, plain objects, and null all behave differently. On the other hand, instanceof can tell you whether something is an Array or Date, but it is less reliable across different execution contexts such as iframes or separate JavaScript realms.

3. Basic Syntax or Core Idea

typeof syntax

Use typeof directly before a value or expression. It always returns a string.

typeof value

Common return values include "string", "number", "boolean", "undefined", "symbol", "bigint", "function", and "object".

instanceof syntax

Use instanceof between an object and a constructor function or class.

value instanceof Constructor

The result is a boolean: true or false.

4. Step-by-Step Examples

Example 1: Checking a primitive with typeof

This example shows the most natural use of typeof: checking a string.

const name = "Ava";

if (typeof name === "string") {
  console.log("Name is a string");
}

This works because typeof returns a simple type label for primitive values.

Example 2: Checking a class instance with instanceof

Use instanceof when you want to know whether an object was created from a specific class.

class User {
  constructor(name) {
    this.name = name;
  }
}

const user = new User("Ava");

if (user instanceof User) {
  console.log("This is a User instance");
}

The check succeeds because user inherits from User.prototype.

Example 3: Distinguishing arrays from plain objects

A common beginner mistake is using typeof to detect arrays. Arrays are objects, so typeof does not identify them specifically.

const items = [1, 2, 3];

console.log(typeof items); // "object"
console.log(items instanceof Array); // true

In modern JavaScript, Array.isArray() is often the best way to check for arrays, but instanceof Array still helps you understand the relationship between an array and its constructor.

Example 4: Checking for built-in object types

instanceof is useful for objects like Date and Map.

const createdAt = new Date();
const settings = new Map();

console.log(createdAt instanceof Date); // true
console.log(settings instanceof Map); // true

This is a good fit when your logic depends on object behavior that comes from a specific built-in prototype.

5. Practical Use Cases

6. Common Mistakes

Mistake 1: Using typeof to detect arrays

typeof cannot distinguish arrays from plain objects because arrays are objects in JavaScript.

Problem: This check treats every object-like value the same, so arrays are misidentified as generic objects.

const value = [1, 2];

if (typeof value === "object") {
  console.log("It is an object");
}

Fix: Use Array.isArray() when you specifically want to know whether a value is an array.

const value = [1, 2];

if (Array.isArray(value)) {
  console.log("It is an array");
}

The corrected version works because Array.isArray() is the dedicated array check.

Mistake 2: Expecting typeof null to return "null"

null is a historical JavaScript quirk. It returns "object" from typeof, which often surprises beginners.

Problem: This logic assumes null has its own type label, so the check fails to detect empty values correctly.

const value = null;

if (typeof value === "null") {
  console.log("No value");
}

Fix: Check value === null directly when you need to detect null specifically.

const value = null;

if (value === null) {
  console.log("No value");
}

This fix works because strict equality checks the actual value instead of the typeof label.

Mistake 3: Using instanceof across different execution contexts

instanceof depends on prototype identity. Objects created in another realm, such as an iframe or a different window, may not match the constructor you expect.

Problem: An object can be a real array or date in another context and still fail instanceof in the current one, producing incorrect results.

const value = someValueFromAnotherWindow;

if (value instanceof Array) {
  console.log("This is an array");
}

Fix: Use checks designed for cross-realm safety when possible, such as Array.isArray() for arrays or a dedicated brand check for your own data structures.

const value = someValueFromAnotherWindow;

if (Array.isArray(value)) {
  console.log("This is an array");
}

The corrected version works better because it does not rely on constructor identity from one specific realm.

7. Best Practices

Practice 1: Use typeof for primitives and functions

typeof is the simplest and clearest tool for basic runtime checks. It is especially useful before calling a callback or handling text input.

function runHandler(handler) {
  if (typeof handler === "function") {
    handler();
  }
}

This keeps the check lightweight and easy to read.

Practice 2: Prefer dedicated helpers for special cases

For arrays, use Array.isArray() instead of instanceof Array when portability matters.

function sum(value) {
  if (!Array.isArray(value)) {
    return 0;
  }

  return value.reduce((total, item) => total + item, 0);
}

This is more robust than relying on object constructors alone.

Practice 3: Validate external data before using it

When data comes from an API, form, or untrusted source, type checks should happen before the value is used.

function formatAge(value) {
  if (typeof value !== "number") {
    return "Unknown age";
  }

  return `Age: ${value}`;
}

Validating early prevents later runtime errors and makes the function easier to reason about.

8. Limitations and Edge Cases

9. Practical Mini Project

In this mini project, we will build a small validator that classifies a value and returns a readable message. It uses typeof for primitives and instanceof for object-based checks.

class Product {
  constructor(name, price) {
    this.name = name;
    this.price = price;
  }
}

function describeValue(value) {
  if (value === null) {
    return "Value is null";
  }

  if (typeof value === "string") {
    return `Text with length ${value.length}`;
  }

  if (typeof value === "number") {
    return `Number: ${value}`;
  }

  if (value instanceof Product) {
    return `Product: ${value.name} costs ${value.price}`;
  }

  if (Array.isArray(value)) {
    return `Array with ${value.length} items`;
  }

  return "Unknown value type";
}

const items = [
  describeValue("hello"),
  describeValue(42),
  describeValue(new Product("Notebook", 9.99)),
  describeValue([1, 2, 3]),
  describeValue(null)
];

console.log(items);

This example shows a practical pattern: use typeof for primitives, a direct null check for null, and instanceof for class instances.

10. Key Points

11. Practice Exercise

Expected output:

string
number
array
book
unknown

Hint: Check primitives with typeof, arrays with Array.isArray(), and class instances with instanceof.

Solution:

class Book {
  constructor(title) {
    this.title = title;
  }
}

function classifyValue(value) {
  if (typeof value === "string") {
    return "string";
  }

  if (typeof value === "number") {
    return "number";
  }

  if (Array.isArray(value)) {
    return "array";
  }

  if (value instanceof Book) {
    return "book";
  }

  return "unknown";
}

console.log(classifyValue("hello"));
console.log(classifyValue(12));
console.log(classifyValue([1, 2]));
console.log(classifyValue(new Book("JavaScript Guide")));
console.log(classifyValue({}));

12. Final Summary

typeof and instanceof solve different problems in JavaScript. typeof is the best first check for primitives, functions, and broad value categories, while instanceof helps you identify whether an object belongs to a constructor-based type.

They are both useful, but neither one is a universal type checker. null needs special handling, arrays are best checked with Array.isArray(), and cross-realm objects can make instanceof less dependable than it first appears.

When you choose the right check for the job, your validation code becomes clearer, safer, and easier to maintain. As a next step, compare these operators with Array.isArray() and Object.prototype.toString.call() so you can recognize the tradeoffs between common type-checking techniques.