TS2349: This expression is not callable

Quick answer

You called a value (value()) whose type isn't callable for all its possibilities. Usually it's a union where only some members are functions — narrow with typeof fn === 'function' first. A () => void | undefined value? Use fn?.(). This is the compile-time guard against the runtime x is not a function.

The exact error string

let fn: (() => void) | number = () => {};
fn();
// error TS2349: This expression is not callable.
//   Not all constituents of type '(() => void) | number' are callable.
//     Type 'number' has no call signatures.

How to diagnose it (read the bottom line)

The last line of the error tells you the situation:

Fix 1: narrow a union to the callable member

if (typeof fn === "function") {
  fn();                          // ✅ narrowed to () => void
}

Fix 2: possibly-undefined function → optional call

type Props = { onClick?: () => void };
function handle(p: Props) {
  p.onClick();                   // ❌ might be undefined
  p.onClick?.();                 // ✅ called only if defined
}

Fix 3: it isn't a function — fix the type or the access

const api = { send: () => {} };
api();                           // ❌ api is an object
api.send();                      // ✅ call the method

Fix 4: overloads — match a signature

If the function is overloaded and your arguments match none of the signatures, the call is reported as not callable. Check the argument count and types against the declared overloads and pass values that fit one.

Worked example: a callback from config/JSON

A handler map is loaded or built dynamically and a looked-up entry might not be a function (a typo'd key, a non-function value in the config). Narrow before calling:

type Handlers = Record<string, (() => void) | undefined>;
const handlers: Handlers = { save: () => {}, /* delete missing */ };

handlers[action]();              // ❌ TS2349 (entry may be undefined)
handlers[action]?.();            // ✅ call only if present and callable

If the map comes from external JSON, type the parsed value (e.g. Record<string, unknown>) and check each entry with typeof === 'function' before calling — JSON can't actually contain functions, so a "callable from JSON" is usually a design smell worth re-checking.

TS2349 in React

// 1) optional event-handler prop
function Modal({ onClose }: { onClose?: () => void }) {
  return <button onClick={() => onClose?.()}>Close</button>;   // ✅ optional call
}

// 2) a ref to a child's imperative handle
const ref = useRef<{ focus: () => void } | null>(null);
ref.current.focus();             // ❌ possibly null + call
ref.current?.focus();            // ✅

Common variants of this message

VariantMeaningFix
Not all constituents ... are callableunion with a non-function membernarrow with typeof
Type 'X' has no call signaturesvalue isn't a functioncall a method / fix the value
type includes undefinedoptional callbackfn?.()
No overload matches this callargs fit no overloadmatch a declared signature
calling a namespace/typeused a type/namespace as a valuereference the actual function

Debugging checklist

Frequently Asked Questions

What does "Type X has no call signatures" mean?

It means the value isn't a function type at all — you tried to call an object, number, or string. The companion message 'not all constituents ... are callable' means it's a union where only some members are functions. Both are TS2349 variants; the first means fix the value, the second means narrow.

How do I call an optional callback safely?

Use optional call syntax: fn?.(). It calls fn only when it is not null/undefined and is a no-op otherwise. This is the cleanest fix for a callback typed (() => void) | undefined, such as an optional React prop onClick?.

Why does narrowing with typeof fix it?

On a union like (() => void) | number, TypeScript can't call it because number has no call signature. if (typeof fn === 'function') narrows the union to just the callable member inside the block, so the call is allowed and type-checked.

Does this prevent the runtime 'x is not a function'?

Yes. TS2349 is the compile-time guard against TypeError: x is not a function. Fixing it properly — narrowing or correcting the type rather than casting — stops that runtime crash from shipping.

Why does an overloaded function report not callable?

If your arguments match none of the declared overload signatures, TypeScript reports the call as not callable / 'no overload matches this call'. Compare the argument count and types to each overload and pass values that fit one of them.

Is casting to any or Function a good fix?

No — (fn as any)() or the Function type both disable argument and return-type checking, so a genuine 'not a function' bug survives to runtime. Narrow the union or give the value a proper callable type instead; cast only after you've verified at runtime that it's callable.

More TypeScript & JSON errors

Browse the full reference, or generate accurate interfaces from your JSON.

JSON to TypeScript TS2339: Property does not exist All Error References
About the author

Pasindu Ishan is a software developer based in Sri Lanka. He builds privacy-first developer tools at JSON Dev Tools.