This TypeScript error occurs when you attempt to invoke a value that doesn't have a call signature—essentially trying to call something that isn't a function. Common causes include calling non-function types, incorrect imports, type mismatches, and union types that confuse the compiler.
TypeScript's type system ensures type safety by tracking which values are callable (functions) and which are not. When you try to invoke an expression using parentheses `()`, TypeScript verifies that the expression has a call signature. If it doesn't, the compiler emits error TS2349: "This expression is not callable." This error typically appears in several scenarios: 1. **Calling a non-function type**: You're trying to call a string, number, object, or other non-function value as if it were a function 2. **Type assertion issues**: The value is actually a function, but TypeScript has been told (via type assertions or incorrect typing) that it's something else 3. **Import/module problems**: You've imported an object instead of a function, or the default export isn't what you expected 4. **Union type confusion**: When working with union types that include functions, TypeScript can't safely determine which type you have Unlike JavaScript, which throws runtime errors when you call non-functions, TypeScript catches these mistakes at compile time, preventing potentially confusing bugs from reaching production.
First, check what type TypeScript thinks the value is. Hover over the identifier in your IDE to see the inferred type:
// WRONG: Calling a string
const message = "Hello, world!";
message(); // Error: This expression is not callable. Type 'String' has no call signatures.
// WRONG: Calling a number
const count = 100;
count(); // Error: This expression is not callable. Type 'Number' has no call signatures.
// CORRECT: Call an actual function
const greet = () => "Hello, world!";
greet(); // Works fineUse console.log(typeof value) at runtime or check the type annotation in your editor to confirm the value is indeed a function.
This error commonly occurs when you import an object/namespace instead of a function. Ensure you're accessing the correct export:
// utils.ts
export const helpers = {
formatDate: (date: Date) => date.toLocaleDateString(),
formatNumber: (num: number) => num.toFixed(2),
};
// WRONG: Importing the whole object
import { helpers } from "./utils";
helpers(); // Error: This expression is not callable
// CORRECT: Access the method property
import { helpers } from "./utils";
helpers.formatDate(new Date()); // Works
// OR: Import a specific function if exported separately
export const formatDate = (date: Date) => date.toLocaleDateString();
import { formatDate } from "./utils";
formatDate(new Date()); // WorksFor default exports with module interop issues:
// Common with libraries like mitt, lodash in NodeNext mode
// WRONG
import mitt from "mitt"; // mitt might be namespace, not function
mitt(); // Error
// CORRECT
import mitt from "mitt";
const emitter = mitt(); // If mitt is the factory, this works
// OR check library docs for correct import syntaxType assertions can override TypeScript's inference, causing it to treat functions as non-callable types:
// WRONG: Asserting a function as a string
const myFunc = (() => "test") as unknown as string;
myFunc(); // Error: This expression is not callable
// CORRECT: Don't use incorrect assertions
const myFunc = () => "test";
myFunc(); // Works
// Example with objects
interface Config {
handler: () => void;
}
const config = {
handler: () => console.log("running"),
} as Config;
config.handler(); // Works because type is correctIf you must use type assertions, ensure the target type includes call signatures:
type CallableType = (...args: any[]) => any;
const func = someValue as unknown as CallableType;
func(); // Now TypeScript knows it's callableWhen a variable can be multiple types (union type), TypeScript won't let you call it unless you prove it's a function:
type Handler = string | (() => string);
// WRONG: Calling without type check
function process(handler: Handler) {
return handler(); // Error: This expression is not callable
}
// CORRECT: Type guard before calling
function process(handler: Handler) {
if (typeof handler === "function") {
return handler(); // TypeScript knows it's a function here
}
return handler; // String case
}
// React example with union types
type FailedContent = string | JSX.Element | (() => JSX.Element);
function renderFailed(content: FailedContent) {
// WRONG
// return content(); // Error
// CORRECT
if (typeof content === "function") {
return content();
}
return content;
}Common type guard patterns:
// For functions
if (typeof value === "function") { /* ... */ }
// For objects with callable properties
if (value && typeof value.method === "function") { /* ... */ }
// Custom type predicate
function isFunction(value: unknown): value is Function {
return typeof value === "function";
}TypeScript may report this error when calling .map(), .filter(), or .reduce() on arrays with complex union types:
// Problem scenario
type Data = string[] | { items: string[] };
function process(data: Data) {
// Error: This expression is not callable
return data.map((item) => item.toUpperCase());
}
// SOLUTION 1: Type guard
function process(data: Data) {
if (Array.isArray(data)) {
return data.map((item) => item.toUpperCase());
}
return data.items.map((item) => item.toUpperCase());
}
// SOLUTION 2: Normalize to array first
function process(data: Data) {
const arr = Array.isArray(data) ? data : data.items;
return arr.map((item) => item.toUpperCase());
}If using libraries with complex types, ensure your TypeScript version is up to date—older versions had bugs with union type inference for built-in methods.
The module and moduleResolution settings can affect how imports are typed, especially with "module": "NodeNext":
// tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}If you're getting "Type 'typeof import(...)' has no call signatures" errors:
1. Check library typings: Some libraries (like mitt, older versions of packages) may not have proper ESM type definitions
2. Use esModuleInterop: Add "esModuleInterop": true to tsconfig.json
3. Access the correct export:
// If library exports object
import * as MyLib from "my-lib";
MyLib.default(); // Call the default export
// OR
import MyLib from "my-lib";
MyLib(); // If default is the function4. Update library: Check if a newer version has better TypeScript support
### Function Overloads and Call Signatures
TypeScript uses call signatures to determine if a type is callable. You can explicitly define call signatures in interfaces and types:
// Interface with call signature
interface Callable {
(): string; // Call signature
property: number;
}
const myFunc: Callable = Object.assign(
() => "result",
{ property: 42 }
);
myFunc(); // Works - has call signature
myFunc.property; // Also works### Generic Constraints for Callable Types
When working with generics, you can constrain type parameters to be callable:
// WRONG: Generic without constraint
function invoke<T>(fn: T) {
return fn(); // Error: This expression is not callable
}
// CORRECT: Constrain T to be callable
function invoke<T extends (...args: any[]) => any>(fn: T) {
return fn(); // Works
}
// Or use Function type (less type-safe)
function invoke(fn: Function) {
return fn(); // Works but loses parameter/return type info
}### Conditional Types and Callable Resolution
Complex conditional types can result in non-callable types in certain branches:
type Result<T> = T extends string ? () => T : T;
function process<T>(value: Result<T>) {
// Error: Can't call - might be T or (() => T)
return value();
}
// Solution: Type narrowing
function process<T>(value: Result<T>) {
if (typeof value === "function") {
return value();
}
return value;
}### React Component Callable Issues
In React with TypeScript, you might encounter this with render props or function components:
type RenderProp = string | (() => JSX.Element);
// WRONG
function MyComponent({ render }: { render: RenderProp }) {
return <div>{render()}</div>; // Error if render is string
}
// CORRECT
function MyComponent({ render }: { render: RenderProp }) {
const content = typeof render === "function" ? render() : render;
return <div>{content}</div>;
}### Debugging with Type Utilities
Use TypeScript utility types to inspect what TypeScript thinks is callable:
// Check if type has call signature
type IsCallable<T> = T extends (...args: any[]) => any ? true : false;
type Test1 = IsCallable<() => void>; // true
type Test2 = IsCallable<string>; // false
type Test3 = IsCallable<typeof Math.random>; // true### Module Augmentation and Declaration Merging
If you're extending third-party types, ensure you don't accidentally remove call signatures:
// WRONG: Replaces instead of merging
declare module "my-lib" {
const myFunc: { property: string }; // Lost call signature
}
// CORRECT: Merge with existing
declare module "my-lib" {
interface MyFunc {
property: string; // Adds property, preserves call signature
}
}Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript