This error means that you’re trying to use a value as a function, but that value isn’t actually a function.

Here are the most common reasons this happens and how to fix them:

1. Typo in a Variable Name

You might have a typo in the name of a function or a variable that holds a function.

Diagnosis: Carefully review the line of code where the error occurs. Check for any spelling mistakes in the identifier you’re trying to call.

Fix: Correct the spelling of the variable or function name to match its declaration.

Example:

function greet(name: string) {
  console.log(`Hello, ${name}!`);
}

greett("World"); // TS2349: Value greett is not a function.

Fix:

function greet(name: string) {
  console.log(`Hello, ${name}!`);
}

greet("World"); // Corrected typo

Why it works: TypeScript requires exact matches for identifiers. Correcting the spelling ensures you’re referencing the actual function.

2. Trying to Call an Object Property That Isn’t a Function

You might be trying to call a property of an object that you think is a function, but it’s actually a different type of value (like a string, number, or another object).

Diagnosis: Use your IDE’s "Go to Definition" feature on the identifier you’re trying to call. Inspect the type of that identifier. If it’s an object, examine the type of the property you’re trying to invoke.

Fix: Ensure that the property you are attempting to call is indeed a function. If it’s not, you’ll need to access it differently or call a different, actual function.

Example:

interface User {
  name: string;
  age: number;
  // Missing a 'greet' method
}

const user: User = {
  name: "Alice",
  age: 30,
};

user.age("Alice"); // TS2349: Value user.age is not a function.

Fix:

interface User {
  name: string;
  age: number;
  greet: (name: string) => void; // Added the greet method
}

const user: User = {
  name: "Alice",
  age: 30,
  greet: (name: string) => {
    console.log(`Hello, ${name}!`);
  },
};

user.greet("Alice"); // Now calling the function property

Why it works: You’ve either added the missing function property or corrected your code to call an existing function property.

3. Forgetting new When Instantiating a Class

When you intend to create an instance of a class, you must use the new keyword. If you omit it, you’re trying to call the class constructor itself as if it were a function, which it is not in this context.

Diagnosis: Check if the identifier you’re trying to call is a class declaration. If it is, look for the new keyword before it.

Fix: Prepend the new keyword to the class name when creating an instance.

Example:

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

let greeter = Greeter("Hello, world!"); // TS2349: Value Greeter is not a function.

Fix:

class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    return "Hello, " + this.greeting;
  }
}

let greeter = new Greeter("Hello, world!"); // Added 'new'

Why it works: The new keyword signals to JavaScript/TypeScript that you intend to create a new object instance based on the class blueprint, invoking the constructor to initialize that instance.

4. Incorrectly Using an import Statement

You might be trying to call something that you’ve imported, but the import itself is not structured correctly, or you’re trying to call the module object directly instead of a named export.

Diagnosis: Examine your import statements. If you’re using a default import (import MyModule from './my-module'), you can call MyModule() if my-module.ts exports a default function. If you’re using named imports (import { myFunction } from './my-module'), you must call myFunction(). Trying to call MyModule() when it’s a named export (or vice-versa) will cause this error.

Fix: Ensure your import statement matches how the module exports its members. If it’s a default export, use import DefaultExport from '...'. If it’s a named export, use import { NamedExport } from '...'.

Example (Default Export Misuse):

// my-module.ts
export default function sayHello() {
  console.log("Hello!");
}

// main.ts
import { sayHello } from './my-module'; // Incorrect: expecting default, got named
sayHello(); // TS2349: Value sayHello is not a function.

Fix:

// my-module.ts
export default function sayHello() {
  console.log("Hello!");
}

// main.ts
import sayHello from './my-module'; // Correct: importing default export
sayHello();

Example (Named Export Misuse):

// my-module.ts
export function sayHello() {
  console.log("Hello!");
}

// main.ts
import sayHello from './my-module'; // Incorrect: expecting named, got default
sayHello(); // TS2349: Value sayHello is not a function.

Fix:

// my-module.ts
export function sayHello() {
  console.log("Hello!");
}

// main.ts
import { sayHello } from './my-module'; // Correct: importing named export
sayHello();

Why it works: This aligns your code’s expectation of what’s being imported with how the module actually exports its members, ensuring you’re trying to call a defined function.

5. Using a Variable Before It’s Assigned a Function

If you declare a variable but don’t assign a function to it before trying to call it, TypeScript will complain. This is especially common with variables declared without an initial value.

Diagnosis: Check the declaration of the variable you’re trying to call. If it’s declared without an initial assignment (e.g., let myFunc: () => void;), and you attempt to call it before assigning a function, this error will occur.

Fix: Assign a function to the variable before you attempt to call it.

Example:

let processData: (data: string) => void;

// ... some other code ...

processData("some data"); // TS2349: Value processData is not a function.

Fix:

let processData: (data: string) => void;

processData = (data: string) => {
  console.log(`Processing: ${data}`);
};

// ... some other code ...

processData("some data");

Why it works: You are now ensuring that the processData variable holds a function reference before you attempt to execute it.

6. Incorrectly Handling Promises

When working with Promises, you might try to call the Promise object itself instead of the resolved value or a function that handles the resolved value.

Diagnosis: If the expression you’re trying to call is related to an asynchronous operation, check if it’s returning a Promise object. You usually need to use .then() or await to access the result.

Fix: Use .then() or await to handle the Promise and access its resolved value or execute a function with it.

Example:

function fetchData(): Promise<string> {
  return Promise.resolve("Some data");
}

const data = fetchData();
data("Processing"); // TS2349: Value data is not a function.

Fix:

function fetchData(): Promise<string> {
  return Promise.resolve("Some data");
}

async function processFetchedData() {
  const data = await fetchData(); // Await the promise
  console.log(`Processing: ${data}`);
}

processFetchedData();

// Or using .then()
fetchData().then(data => {
  console.log(`Processing: ${data}`);
});

Why it works: You’re correctly unwrapping the Promise to get the actual data before attempting to use it, or you’re passing the data to a function that expects it.

After fixing this, you’ll likely encounter TS2551: Property '...' does not exist on type '...'. Did you mean '...'? if you made a typo that was previously masked by this error, or if you’ve introduced a new type mismatch.

Want structured learning?

Take the full Typescript course →