Skip to main content

How to Check if a Value is a Promise in JavaScript

In modern asynchronous JavaScript, it's common to work with functions that might return a direct value or a Promise that will resolve to a value. To handle both cases uniformly, you need a reliable way to determine if a given value is a "thenable"—an object that behaves like a Promise (i.e., has a .then() method).

This guide will explain why you often don't need a strict "is this a promise?" check. Instead, it will teach you the modern, idiomatic solution for handling any value as if it were a promise by using Promise.resolve(). We will also cover the classic "duck typing" method for when you need to explicitly check a value's shape.

The Core Task: Handling a Value That Might Be a Promise

Often, the goal isn't just to ask "is this a promise?" but rather to ensure you can use .then() on a value, regardless of whether it's a Promise or a direct value.

Example of code with problems:

function processData(data) {
// If `data` is the number 42, this will fail.
// ⛔️ Uncaught TypeError: data.then is not a function
data.then(result => {
console.log(result);
});
}

// This call works
processData(Promise.resolve(42));

// This call fails
processData(42);

The Promise.resolve() method is the perfect tool for this. It is designed to "wrap" a value in a Promise.

The Logic

  • If you pass a Promise to Promise.resolve(), it returns that same Promise.
  • If you pass a non-Promise value (like a number or a string), it returns a new Promise that immediately resolves with that value.

This means the return value of Promise.resolve() is always a Promise, so you can safely call .then() on it.

Solution:

function processData(data) {
// ✅ Wrap the input in Promise.resolve() to guarantee it's a Promise
Promise.resolve(data).then(result => {
console.log(result);
});
}

// This call now works
processData(Promise.resolve(42)); // Output: 42

// This call also works
processData(42); // Output: 42
note

This is the idiomatic, modern, and recommended way to handle values that might be "thenable."

The Classic Method: "Duck Typing" to Check for .then()

If you truly need to check if a value is like a Promise and return a boolean, you can use a technique called "duck typing." The principle is: "If it walks like a duck and it quacks like a duck, then it must be a duck." In our case, if a value is an object and has a .then() method, we can consider it "thenable" (promise-like).

Solution:

function isThenable(value) {
return value !== null &&
typeof value === 'object' &&
typeof value.then === 'function';
}

const myPromise = new Promise(resolve => resolve());
const myObject = { id: 1 };
const myNumber = 42;

console.log(isThenable(myPromise)); // Output: true
console.log(isThenable(myObject)); // Output: false
console.log(isThenable(myNumber)); // Output: false

// Be aware of the limitation:
const fakePromise = { then: () => {} };
console.log(isThenable(fakePromise)); // Output: true

How it Works:

  1. value !== null: This is a crucial first check because typeof null is paradoxically 'object'.
  2. typeof value === 'object': Ensures the value is an object.
  3. typeof value.then === 'function': Checks if it has a .then property that is a function.

How the Methods Work

  • Promise.resolve(): This is a static method of the Promise class that is part of the ECMAScript standard. It is designed specifically for standardizing values into a promise-based workflow.
  • Duck Typing: This is a logical check based on an object's properties rather than its specific type or class. It is a common pattern in dynamically-typed languages like JavaScript. Its main weakness is that it can be fooled by an object that coincidentally has the same method names as a Promise.

Conclusion

When dealing with values that may or may not be a Promise, it's important to choose the right tool for the job.

The key takeaways are:

  1. If your goal is to handle a value in a promise-based workflow, the Promise.resolve(value) method is the recommended best practice. It safely converts any value into a Promise, allowing you to use .then() on it without needing to check its type first.
  2. If your goal is to strictly check if a value has the shape of a Promise and return a boolean, you can use "duck typing" to check if the value is an object with a .then() method.

For most modern asynchronous code, the Promise.resolve() pattern is the cleaner and more idiomatic solution.