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.
- typeof answers: “What broad kind of value is this?”
- instanceof answers: “Is this object related to this constructor or class?”
- typeof works best with primitives and functions.
- instanceof works best with objects.
- They are not interchangeable, even when both seem to work in simple examples.
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 valueCommon 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 ConstructorThe 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); // trueIn 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); // trueThis is a good fit when your logic depends on object behavior that comes from a specific built-in prototype.
5. Practical Use Cases
- Validate user input before calling code that expects a string, number, or function.
- Check whether a value is callable before invoking it as a callback.
- Detect whether a value is a class instance in business logic or data transformation code.
- Handle arrays separately from plain objects when normalizing API responses.
- Write safer guard clauses in utility functions and custom validators.
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
- typeof null returns "object", which is a long-standing language quirk.
- typeof cannot distinguish arrays, dates, and plain objects.
- instanceof depends on the prototype chain, so objects from other realms may fail the check unexpectedly.
- instanceof only works with callable constructors or classes on the right-hand side; using a non-constructor can throw an error.
- Objects created with Object.create(null) do not inherit from Object.prototype, so some assumptions about object methods do not apply.
- Subclassing affects instanceof because derived objects are also instances of their parent classes.
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
- typeof returns a string that describes broad JavaScript value categories.
- instanceof returns a boolean based on the prototype chain.
- typeof is best for primitives and functions.
- instanceof is best for checking object instances created by classes or constructors.
- null is a special case because typeof null returns "object".
- For arrays, Array.isArray() is usually the safest choice.
- Cross-realm objects can make instanceof less reliable.
11. Practice Exercise
- Create a function named classifyValue.
- If the input is a string, return "string".
- If the input is a number, return "number".
- If the input is an array, return "array".
- If the input is an instance of a custom class named Book, return "book".
- Otherwise return "unknown".
Expected output:
string
number
array
book
unknownHint: 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.