Skip to content

isThenable

Checks whether a value is a thenable — an object or function with a callable then method that matches the minimal PromiseLike<T> shape. This helper is intentionally narrow and does not attempt to validate full Promise behavior, only the presence and type of then.

It never mutates input and never invokes the then method. Use it when you need to branch on "can I treat this like a Promise-like value?" before attaching handlers or normalizing to a concrete Promise.

Signature

function isThenable<T = unknown>(value: unknown): value is PromiseLike<T>

Parameters

Name Type Description
value unknown The value to normalize.

Returns

  • true: If value is not null or undefined, is an object or function, and has a then property whose type is function.
  • false: For all other values, including primitives, objects without then, and objects whose then property is not a function.

Behavior

  • Accepts both objects and functions as potential thenables.
  • Rejects null and undefined immediately.
  • Requires a then, own, or inherited property whose value is a function.
  • Does not invoke then; it only checks for the presence and type of the method.
  • Does not coerce or wrap values; the original value is preserved.
  • Never mutates input.
  • The current implementation directly accesses the then property; if a value exposes a hostile then getter that throws, this helper will propagate that exception rather than swallowing it.

Examples

isThenable(Promise.resolve(1));
// true (narrowed to PromiseLike<number>)

isThenable({
  then(onFulfilled: (value: string) => void) {
    onFulfilled("ok");
  },
});
// true (custom thenable)

const fnThenable = Object.assign(
  () => "value",
  {
    then(onFulfilled: (value: number) => void) {
      onFulfilled(42);
    },
  },
);

isThenable(fnThenable);
// true (functions with then are supported)

isThenable(123);
// false

isThenable({ then: "not-a-function" });
// false

isThenable(null);
// false

declare const maybeThenable: unknown;

if (isThenable<{ id: number }>(maybeThenable)) {
  maybeThenable.then((value) => {
    // value is { id: number } here
  });
}

Notes

  • This helper deliberately targets the minimal and widely used PromiseLike<T> pattern: "has a callable then". It does not assert on catch, finally, or Promise brand-specific behavior.
  • Because it only checks shape, plain objects and functions with a compatible then method are accepted, which matches how the Promise resolution algorithm itself treats thenables.
  • The generic parameter T exists purely for type narrowing and does not affect runtime behavior; it lets you line up the runtime check with the expected fulfillment type when working with unknown.
  • The helper never invokes then and never constructs new Promises. It is suitable as a low-level building block in higher-level normalization helpers that may wrap thenables in concrete Promises or branch between sync and async paths.