Fix: TypeError: x is not a function
Quick Answer
How to fix JavaScript TypeError is not a function caused by wrong variable types, missing imports, overwritten variables, incorrect method names, and callback issues.
The Error
You run JavaScript code and get:
TypeError: myFunction is not a functionOr variations:
TypeError: response.json is not a functionTypeError: arr.map is not a functionTypeError: document.getElementById(...).addEventListener is not a functionTypeError: (intermediate value)(...) is not a functionUncaught TypeError: this.setState is not a functionJavaScript tried to call something as a function, but the value is not a function. It could be undefined, null, a string, a number, an object, or any other non-function type.
Why This Happens
When you write something(), JavaScript expects something to be a function (or a callable object). If it is anything else — undefined, null, a number, a string, an object — the engine throws TypeError.
Common causes:
- Typo in the function name.
documnet.getElementByIdinstead ofdocument.getElementById. - Variable is not what you think. A variable was reassigned, overwritten, or shadowed by another declaration.
- Missing or wrong import. The module does not export the function you are trying to use.
- Calling a method on the wrong type.
"hello".map()— strings do not have amapmethod. - Calling parentheses on a non-function. Two expressions next to each other without a semicolon:
const a = {}(function() {})(). thiscontext lost. A method extracted from an object loses itsthisbinding.- Async/await mistake. Calling
.then()on a non-Promise, or forgetting toawaita function that returns an object.
Fix 1: Check the Variable Type
Before calling something as a function, verify what it actually is:
console.log(typeof myFunction); // Should be "function"
console.log(myFunction); // See the actual value
console.log(typeof myFunction === "function"); // true or falseIf it prints undefined, the variable was never assigned a function. If it prints object, string, or number, it was assigned something else.
Common case — variable overwritten:
let filter = (arr) => arr.filter(x => x > 0);
// Later, accidentally overwritten:
const filter = document.getElementById("filter"); // Now it's an HTML element!
filter([1, -2, 3]); // TypeError: filter is not a functionRename one of the variables to avoid the conflict.
Pro Tip: Use
constinstead ofletwhenever possible. If the variable isconst, you get an error at the point of reassignment instead of a confusingTypeErrorlater. This makes bugs easier to find.
Fix 2: Fix Missing or Wrong Imports
A common cause in module-based code. The function you imported might not exist in the module:
Broken — wrong import:
// The module exports { fetchUser } but you import fetchUsers (plural)
import { fetchUsers } from "./api.js";
fetchUsers(); // TypeError: fetchUsers is not a functionFixed:
import { fetchUser } from "./api.js";
fetchUser();Broken — default vs. named import confusion:
// Module exports: export default function myFunc() {}
import { myFunc } from "./module.js"; // Wrong — named import
myFunc(); // TypeError: myFunc is not a function
// Fixed:
import myFunc from "./module.js"; // Correct — default importCheck what the module exports:
import * as myModule from "./module.js";
console.log(myModule); // See all exportsFor module import resolution issues, see Fix: Module not found: Can’t resolve.
Fix 3: Fix .map() on Non-Arrays
arr.map is not a function usually means arr is not an array:
const data = fetchData(); // Returns an object, not an array
data.map(item => item.name); // TypeError: data.map is not a functionFix: Check if the value is an array:
console.log(Array.isArray(data)); // false
console.log(data); // { results: [...] }Fix: Access the actual array inside the response:
const data = fetchData();
data.results.map(item => item.name); // Access the array propertyFix: Convert to an array if needed:
// Object to array of entries
Object.entries(data).map(([key, value]) => `${key}: ${value}`);
// Object values to array
Object.values(data).map(item => item.name);
// String to array
const chars = Array.from("hello"); // ["h", "e", "l", "l", "o"]Fix: Handle the case where data might not be an array:
const items = Array.isArray(data) ? data : [];
items.map(item => item.name);If the data is coming from an API and might be null or undefined, see Fix: TypeError: Cannot read properties of undefined.
Fix 4: Fix this Context Issues
When you extract a method from an object, this is no longer bound to the object:
Broken:
class Timer {
constructor() {
this.seconds = 0;
}
start() {
setInterval(this.tick, 1000); // `this` is lost inside setInterval
}
tick() {
this.seconds++; // TypeError: Cannot read properties of undefined
console.log(this.seconds);
}
}Fixed — bind the method:
start() {
setInterval(this.tick.bind(this), 1000);
}Fixed — use an arrow function:
start() {
setInterval(() => this.tick(), 1000);
}Fixed — define as an arrow function property:
class Timer {
seconds = 0;
tick = () => {
this.seconds++;
console.log(this.seconds);
};
start() {
setInterval(this.tick, 1000);
}
}Arrow functions capture this from the enclosing scope, so they always use the correct context.
React-specific: In React class components, event handlers lose this context:
class MyComponent extends React.Component {
handleClick() {
this.setState({ clicked: true }); // TypeError: this.setState is not a function
}
render() {
return <button onClick={this.handleClick}>Click</button>;
}
}Fix by binding in the constructor or using an arrow function:
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}Or:
handleClick = () => {
this.setState({ clicked: true });
};Fix 5: Fix Missing Semicolons (IIFE Issues)
JavaScript’s automatic semicolon insertion (ASI) can cause unexpected is not a function errors:
Broken:
const a = { name: "Alice" }
(function() {
console.log("IIFE");
})()JavaScript interprets this as { name: "Alice" }(function() { ... })() — calling the object as a function.
Fixed — add a semicolon:
const a = { name: "Alice" };
(function() {
console.log("IIFE");
})();This happens whenever a line starts with (, [, or a template literal ` and the previous line does not end with a semicolon.
Common Mistake: Relying on ASI (automatic semicolon insertion) without understanding its rules. ASI does NOT insert a semicolon before
(,[,/,+,-, or`. If your coding style omits semicolons, prefix lines starting with these characters with a;:;(function() { ... })() ;[1, 2, 3].forEach(...)
Fix 6: Fix .json() and Fetch API Issues
response.json is not a function usually means you are calling .json() on something that is not a Response object:
Broken — already parsed:
fetch("/api/data")
.then(res => res.json())
.then(data => data.json()) // TypeError: data.json is not a functionAfter .json() is called once, the result is a plain object, not a Response. You cannot call .json() again.
Fixed:
fetch("/api/data")
.then(res => res.json())
.then(data => {
console.log(data); // Already parsed — use it directly
});Broken — response is not a fetch Response:
// axios returns parsed data directly, no .json() needed
const response = await axios.get("/api/data");
response.json(); // TypeError: response.json is not a function
// Fixed:
const data = response.data; // axios puts parsed data in .dataFix 7: Fix Callback and Higher-Order Function Issues
When passing functions as callbacks, make sure you pass the function, not the result of calling it:
Broken — calling the function instead of passing it:
button.addEventListener("click", handleClick());
// handleClick() is called immediately, and its return value
// (likely undefined) is passed as the listenerFixed — pass the function reference:
button.addEventListener("click", handleClick);Broken — wrong method name:
const arr = [1, 2, 3];
arr.forEach(item => {
console.log(item.toUpperCase()); // TypeError: item.toUpperCase is not a function
// item is a number, not a string
});Fixed:
const arr = [1, 2, 3];
arr.forEach(item => {
console.log(String(item)); // Convert to string first
});Fix 8: Fix Constructor and Class Issues
Broken — calling a class without new:
class User {
constructor(name) {
this.name = name;
}
}
const user = User("Alice"); // TypeError: Class constructor User cannot be invoked without 'new'Fixed:
const user = new User("Alice");Broken — importing a non-default export as a constructor:
// Module exports: export function createUser(name) { ... }
import createUser from "./user.js"; // Wrong — default import
const user = new createUser("Alice"); // TypeError: createUser is not a constructorFixed:
import { createUser } from "./user.js"; // Named import
const user = createUser("Alice"); // It's a factory function, not a classFix 9: Fix Optional Chaining for Safe Calls
If a function might not exist, use optional chaining:
// Might throw TypeError if onSuccess is undefined
onSuccess(data);
// Safe — only calls if onSuccess is a function
onSuccess?.(data);Check before calling:
if (typeof onSuccess === "function") {
onSuccess(data);
}Optional chaining (?.()) is cleaner for optional callbacks. Use the explicit check when you need to handle the missing function case differently.
Still Not Working?
If you have checked all the fixes above and still get this error:
Check for circular dependencies. If module A imports from module B, and module B imports from module A, one of them might get undefined for the imported function. See Fix: cannot use import statement outside a module for related module issues.
Check for minification issues. Minifiers can rename or remove functions. If the error only appears in production (minified) code, check your build output and source maps.
Check for browser compatibility. Some functions are not available in older browsers. Array.at(), Object.hasOwn(), structuredClone() are relatively new. Check MDN for browser support tables.
Check for prototype pollution. If a library or your own code modifies Object.prototype or Array.prototype, built-in methods might be overwritten. Avoid modifying built-in prototypes.
Check for Web Workers or iframes. Arrays created in a different execution context (iframe, Web Worker) have a different Array constructor. instanceof Array returns false, and methods might not work as expected. Use Array.isArray() instead of instanceof Array.
Use the browser debugger. Set a breakpoint on the line that throws. Inspect the value being called to see exactly what it is and where it came from. The browser’s call stack shows how you got there.
For TypeScript, the compiler catches most of these errors at compile time. If you are seeing this error in a TypeScript project, check for any types or incorrect type assertions that bypass type checking. See Fix: TypeScript property does not exist on type for related type issues.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: TypeScript Argument of type 'X' is not assignable to parameter of type 'Y' (TS2345)
How to fix TypeScript error TS2345 Argument of type is not assignable to parameter of type, covering null narrowing, union types, generics, callback types, type widening, enums, and React event handlers.
Fix: TypeScript Could not find a declaration file for module (TS7016)
How to fix the TypeScript TS7016 error 'Could not find a declaration file for module' by installing @types packages, creating declaration files, and configuring tsconfig.json.
Fix: TypeScript Property does not exist on type (TS2339)
How to fix TypeScript error TS2339 'Property does not exist on type'. Covers missing interface properties, type narrowing, optional chaining, intersection types, index signatures, type assertions, type guards, window augmentation, and discriminated unions.
Fix: TypeScript Type 'X | undefined' is not assignable to type 'X'
How to fix TypeScript strict null checks error Type X undefined is not assignable caused by optional values, nullable types, missing guards, and strictNullChecks.