Skip to content

isCallable

Checks whether a value is callable — meaning it can be invoked with () without throwing a TypeError due to a lack of callability. This helper distinguishes between ordinary functions and ES2015 class constructors, which have typeof "function" but cannot be invoked without new.

It never throws and never mutates input. Use it when you need to branch on "is this something I can safely call?" before performing higher-level normalization or validation.

Signature

function isCallable(value: unknown): value is (...args: unknown[]) => unknown

Parameters

Name Data type Description
value unknown The value to normalize to a non-empty string.

Returns

  • true: If value is a function and not an ES2015 class constructor.
  • false: For all non-functions, class constructors, and values whose toString implementation is missing, malformed, or throws.

Behavior

  • Accepts all normal callable functions: arrow, async, generator, bound, and functions created with the Function constructor.
  • Rejects ES2015 classes by inspecting the function’s own toString() output.

  • Never throws:

  • If accessing or calling .toString throws, the helper returns false.
  • If .toString is missing or not callable, the helper returns true (treating the value as a normal function).
  • Never mutates input.
  • Never invokes the function itself.
  • Time complexity is O(1).

Examples

isCallable(() => 1)
// true

isCallable(async () => "ok")
// true

function* gen() { yield 1 }
isCallable(gen)
// true

class MyClass {}
isCallable(MyClass)
// false

isCallable(123)
// false

// Fake class via overridden toString
const fn = function () {}
Object.defineProperty(fn, "toString", {
  value() { return "class FakeClass {}" }
})
isCallable(fn)
// false

declare const maybeFn: unknown

if (isCallable(maybeFn)) {
  const result = maybeFn("hello")
  // result is unknown, but the call is now type-safe
}

Notes

  • ES2015 classes always stringify with a leading class keyword, which makes them reliably detectable without invoking them.
  • Hostile or malformed toString implementations are treated as non-callable to preserve safety and avoid throwing.
  • This helper is intentionally minimal: it does not validate arity, return type, or safety of invocation — only whether the value is structurally callable.
  • Suitable for low-level guards used by higher-level validators, normalizers, and async/sync branching logic.