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 whosetoStringimplementation is missing, malformed, or throws.
Behavior
- Accepts all normal callable functions: arrow, async, generator, bound, and functions created with the
Functionconstructor. -
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
toStringimplementations 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.