Skip to content

How to Check if a Value is a Promise in JavaScript

Learn how to safely handle values that might be Promises in JavaScript using Promise.resolve() or duck typing to check for .then() method support.

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

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.

Navigation