【JavaScript】「is not a function」エラーの原因と解決方法|全パターン完全解説

【JavaScript】「is not a function」エラーの原因と解決方法|全パターン完全解説 JavaScript

JavaScriptを書いていると、ブラウザのコンソールにTypeError: X is not a functionというエラーが表示されることがあります。このエラーは関数でないものを関数として呼び出そうとしたときに発生する、JavaScript開発で最も頻繁に遭遇するエラーの一つです。

この記事では、「is not a function」エラーが発生するすべてのパターンを網羅的に解説します。変数名の衝突、配列メソッドの誤用、DOM操作、コールバック関数、非同期処理、外部ライブラリ、クラス・コンストラクタなど、実務で遭遇するあらゆるケースについてエラーの再現コード修正方法をセットで紹介します。

この記事で学べること

  • 「TypeError: X is not a function」エラーの根本原因と読み方
  • 変数名・関数名の衝突によるエラーと解決方法
  • オブジェクトのメソッド呼び出しミスの全パターン
  • 配列メソッド(map, filter, forEach等)の誤用と修正方法
  • コールバック関数・DOM操作・非同期処理でのエラー対策
  • 外部ライブラリ・モジュールの読み込み問題の解決
  • クラス・コンストラクタでのエラーパターン
  • 実務で使えるデバッグテクニックと予防策
スポンサーリンク
  1. 「is not a function」エラーとは?
    1. エラーメッセージの読み方
    2. なぜこのエラーが発生するのか
    3. エラーの根本原因を理解する
    4. コンソールでのエラーの見方
    5. typeof で型を確認する方法
  2. 変数名・関数名の衝突
    1. 同名の変数で関数が上書きされるパターン
    2. 関数の戻り値を同名の変数に代入するパターン
    3. グローバル変数との衝突
    4. let / const / var と関数宣言の巻き上げ(hoisting)
    5. 即時実行関数(IIFE)でのセミコロン問題
  3. オブジェクトのメソッド呼び出しミス
    1. 存在しないメソッド名のタイポ
    2. プロパティ(値)をメソッド(関数)として呼び出した
    3. prototype メソッドの呼び出しミス
    4. this のコンテキスト消失
    5. メソッドを変数に取り出して呼び出すパターン
  4. 配列メソッドの誤用
    1. 配列でないものに配列メソッドを使った
    2. querySelectorAll の戻り値に配列メソッドを使った
    3. arguments オブジェクトに配列メソッドを使った
    4. API レスポンスが期待と異なる型だった
  5. コールバック関数でのエラー
    1. undefined をコールバックとして渡した
    2. 関数の戻り値をコールバックとして渡した(func() vs func)
    3. addEventListener での問題
    4. 配列メソッドのコールバックが undefined
  6. DOM操作でのエラー
    1. querySelector が null を返す場合
    2. DOMContentLoaded 前にスクリプトが実行される
    3. HTMLCollection と NodeList の違い
  7. 非同期処理でのエラー
    1. Promise の then / catch が関数でない
    2. async/await での誤用
    3. fetch のレスポンス処理ミス
    4. setTimeout / setInterval の引数ミス
  8. 外部ライブラリ・モジュールでのエラー
    1. ライブラリの読み込み順序
    2. CDN の読み込み失敗
    3. import / require のミス(default export vs named export)
    4. jQuery の $ が未定義
    5. ライブラリのバージョン違い
  9. クラス・コンストラクタでのエラー
    1. new を忘れた場合
    2. static メソッドとインスタンスメソッドの混同
    3. 継承時の super 呼び出しミス
    4. private メソッドへのアクセス
  10. デバッグテクニック
    1. typeof でチェックする
    2. console.log で確認する
    3. try-catch で安全に呼び出す
    4. Optional chaining(?.)の活用
    5. ブラウザデベロッパーツールの使い方
  11. 実務でよくあるパターン10選
    1. パターン1: getElementById().addEventListener() で null
    2. パターン2: JSON.parse の結果にメソッド呼び出し
    3. パターン3: map / filter をオブジェクトに使う
    4. パターン4: String / Number のメソッド名タイポ
    5. パターン5: window.onload の二重定義
    6. パターン6: forEach の戻り値を使おうとする
    7. パターン7: Promise を await し忘れる
    8. パターン8: 分割代入で関数を壊す
    9. パターン9: reduce の初期値を忘れる
    10. パターン10: チェーン中の null
  12. まとめ
    1. 「is not a function」解決フローチャート
    2. 関連エラーとの違い
    3. 予防のためのベストプラクティス

「is not a function」エラーとは?

TypeError: X is not a function」は、JavaScriptの実行時エラー(ランタイムエラー)の一種です。コード中で関数ではないものに対して ()(関数呼び出し演算子)を使ったときに発生します。

エラーメッセージの読み方

このエラーメッセージは、ブラウザによって若干表示が異なります。

Chrome / Edge:
Uncaught TypeError: xxx is not a function

Firefox:
TypeError: xxx is not a function

Safari:
TypeError: xxx is not a function. (In "xxx()", "xxx" is undefined)

エラーメッセージの「xxx」の部分には、関数として呼び出そうとした変数名やプロパティ名が入ります。この名前を手がかりに原因を特定します。

なぜこのエラーが発生するのか

JavaScriptでは、() を付けて呼び出せるのは関数(function)型の値だけです。関数以外の値(undefined、null、数値、文字列、オブジェクト、配列など)に () を付けると、このエラーが発生します。

エラーが発生する基本例
// undefined を関数として呼び出す
let myFunc = undefined;
myFunc();  // TypeError: myFunc is not a function

// 数値を関数として呼び出す
let num = 42;
num();  // TypeError: num is not a function

// 文字列を関数として呼び出す
let str = "hello";
str();  // TypeError: str is not a function

// null を関数として呼び出す
let obj = null;
obj();  // TypeError: obj is not a function

エラーの根本原因を理解する

このエラーが発生する根本原因は、次の3つに分類できます。

分類 原因
値が undefined / null 変数に関数が代入されていない、またはプロパティが存在しない undefined()
値が別の型 変数に数値・文字列・オブジェクトなど関数以外の値が入っている "hello"()
メソッド名の間違い 存在しないメソッド名を呼び出した(タイポ含む) arr.foerach()

コンソールでのエラーの見方

ブラウザの開発者ツール(DevTools)のコンソールタブでエラーを確認できます。エラーメッセージにはスタックトレースが含まれており、どのファイルの何行目でエラーが起きたかがわかります。

コンソールエラーの読み方
Uncaught TypeError: myFunction is not a function
    at doSomething (script.js:15:3)
    at main (script.js:25:5)
    at script.js:30:1

// 読み方:
// 1行目: エラーの種類とメッセージ
//   → myFunction が関数ではないのに呼び出された
// 2行目以降: スタックトレース(コールスタック)
//   → script.js の15行目、doSomething 関数内で発生

ポイント:エラーメッセージの「is not a function」の直前にある名前が問題の変数やプロパティです。その変数が「なぜ関数でないか」を調べることが解決の第一歩です。

typeof で型を確認する方法

変数が関数かどうかは typeof 演算子で確認できます。関数であれば "function" が返ります。

typeof で関数かどうか確認
function greet() { return "Hello"; }
const num = 42;
const str = "hello";
const obj = {};

console.log(typeof greet);  // "function" ← 呼び出しOK
console.log(typeof num);    // "number"   ← 呼び出しNG
console.log(typeof str);    // "string"   ← 呼び出しNG
console.log(typeof obj);    // "object"   ← 呼び出しNG

変数名・関数名の衝突

「is not a function」エラーの最も一般的な原因の一つが、変数名と関数名の衝突です。同じ名前の変数が関数を上書きしてしまい、関数として呼び出せなくなるパターンです。

同名の変数で関数が上書きされるパターン

JavaScriptでは、関数と同じ名前の変数を宣言すると、関数が上書きされてしまうことがあります。

Uncaught TypeError: getData is not a function

エラーが出るコード
// 関数を定義
function getData() {
  return { name: "Alice", age: 25 };
}

// 同じ名前の変数で上書きしてしまう
var getData = "user data";

// 関数を呼び出そうとするとエラー
getData();  // TypeError: getData is not a function
// getData は文字列 "user data" になっている
修正後のコード
// 関数を定義
function getData() {
  return { name: "Alice", age: 25 };
}

// 異なる名前を使う
const userData = "user data";

// 正常に呼び出せる
const result = getData();
console.log(result);  // {{ name: "Alice", age: 25 }}

関数の戻り値を同名の変数に代入するパターン

関数の実行結果を同じ名前の変数に代入してしまい、2回目の呼び出しでエラーになるケースです。

Uncaught TypeError: getConfig is not a function

エラーが出るコード
function getConfig() {
  return { debug: true, version: "1.0" };
}

// 戻り値を同名の変数に代入(関数が上書きされる)
var getConfig = getConfig();

// 2回目の呼び出しでエラー
getConfig();  // TypeError: getConfig is not a function
// getConfig はオブジェクト {{ debug: true, version: "1.0" }} になっている
修正後のコード
function getConfig() {
  return { debug: true, version: "1.0" };
}

// 別の名前で受け取る
const config = getConfig();
const config2 = getConfig();
console.log(config);  // {{ debug: true, version: "1.0" }}

グローバル変数との衝突

JavaScriptのグローバルオブジェクト(window)にはデフォルトで多くのプロパティが存在します。同名の変数を定義すると衝突が起きることがあります。

Uncaught TypeError: alert is not a function

エラーが出るコード
// グローバル関数 alert を変数で上書き
var alert = "警告メッセージ";

// 元の alert() が使えなくなる
alert("Hello");  // TypeError: alert is not a function
修正後のコード
// グローバル関数と衝突しない名前を使う
const alertMessage = "警告メッセージ";

// alert() は正常に使える
alert("Hello");  // 正常動作

// もしくは window.alert で明示的に呼び出す
window.alert("Hello");  // 確実に動作

注意:グローバル変数として使われやすい名前(alert, confirm, prompt, open, close, name, status など)は、変数名として使わないようにしましょう。

let / const / var と関数宣言の巻き上げ(hoisting)

JavaScriptの巻き上げ(hoisting)の挙動は、宣言の種類によって異なります。これが「is not a function」エラーの原因になることがあります。

Uncaught TypeError: greet is not a function

var による関数式は巻き上げされない
// 宣言前に呼び出そうとする
greet();  // TypeError: greet is not a function

// var で関数式を定義
var greet = function() {
  console.log("Hello!");
};

// var greet は巻き上げされるが、値は undefined
// つまり実行時には greet = undefined の状態で greet() が呼ばれる
修正方法1: 関数宣言を使う(巻き上げされる)
// 関数宣言は巻き上げされるので、宣言前に呼べる
greet();  // "Hello!" ← 正常動作

function greet() {
  console.log("Hello!");
}
修正方法2: 宣言後に呼び出す
// 先に定義してから呼び出す
const greet = function() {
  console.log("Hello!");
};

greet();  // "Hello!" ← 正常動作
宣言の種類 巻き上げ 宣言前に呼び出し
function 宣言 関数全体が巻き上げ OK(正常動作)
var 関数式 変数名だけ巻き上げ(値は undefined) TypeError: is not a function
let / const 関数式 TDZ(一時的デッドゾーン) ReferenceError
アロー関数(const) TDZ(一時的デッドゾーン) ReferenceError

即時実行関数(IIFE)でのセミコロン問題

即時実行関数(IIFE)の前にセミコロンがないと、前の文と結合されてエラーになることがあります。

Uncaught TypeError: (intermediate value)(…) is not a function

エラーが出るコード
// セミコロンなしの変数宣言
const obj = { name: "Alice" }

// すぐ後にIIFEを書くと、obj{{...}}(...) と解釈される
(function() {
  console.log("IIFE実行");
})();
// TypeError: (intermediate value)(...) is not a function
修正後のコード
// 方法1: セミコロンを付ける
const obj = { name: "Alice" };

(function() {
  console.log("IIFE実行");
})();

// 方法2: IIFE の前にセミコロンを置く(防御的セミコロン)
const obj2 = { name: "Bob" }

;(function() {
  console.log("IIFE実行");
})();

ポイント:IIFE(即時実行関数)の前に防御的セミコロン ; を置くパターンは、jQueryプラグインなどでよく見られます。複数のファイルを結合する際のエラーを防ぐテクニックです。

オブジェクトのメソッド呼び出しミス

オブジェクトのメソッドを呼び出す際に「is not a function」が発生するパターンを解説します。タイポ、プロパティとメソッドの混同、this のコンテキスト消失など、さまざまな原因があります。

存在しないメソッド名のタイポ

メソッド名のスペルミスは非常によくある原因です。存在しないプロパティにアクセスすると undefined が返り、それを関数として呼び出すとエラーになります。

Uncaught TypeError: arr.foerach is not a function

エラーが出るコード(タイポの例)
const arr = [1, 2, 3];

// forEach のスペルミス
arr.foerach(function(item) {
  console.log(item);
});
// TypeError: arr.foerach is not a function

// よくあるタイポ:
// arr.foerach()  → arr.forEach()
// str.touppercase() → str.toUpperCase()
// arr.inclues() → arr.includes()
// obj.hasOwnPropery() → obj.hasOwnProperty()
修正後のコード
const arr = [1, 2, 3];

// 正しいスペル: forEach
arr.forEach(function(item) {
  console.log(item);
});
// 1, 2, 3

よくあるメソッド名のタイポをまとめます。

間違い(タイポ) 正しいメソッド名 対象
foerach / foreach forEach Array
touppercase / toUppercase toUpperCase String
tolowercase / toLowercase toLowerCase String
inclues / include includes Array / String
hasOwnPropery hasOwnProperty Object
addEventListner addEventListener EventTarget
getElementByld getElementById Document
queryselector querySelector Document / Element
stringfy / Stringify stringify JSON
parseint / Parseint parseInt Global

プロパティ(値)をメソッド(関数)として呼び出した

オブジェクトのプロパティが関数ではなく値(文字列・数値など)なのに、() を付けて呼び出そうとするパターンです。

Uncaught TypeError: user.name is not a function

エラーが出るコード
const user = {
  name: "Alice",
  age: 25
};

// name はプロパティ(文字列)なのに関数として呼び出している
console.log(user.name());  // TypeError: user.name is not a function
修正後のコード
const user = {
  name: "Alice",
  age: 25
};

// プロパティアクセスには () を付けない
console.log(user.name);  // "Alice"

// メソッドとして定義したい場合
const user2 = {
  _name: "Alice",
  name() { return this._name; }
};
console.log(user2.name());  // "Alice"

prototype メソッドの呼び出しミス

静的メソッドとインスタンスメソッドを混同すると、このエラーが発生します。

Uncaught TypeError: Array.push is not a function

エラーが出るコード
// Array(コンストラクタ)にインスタンスメソッドを呼ぼうとする
Array.push(1);  // TypeError: Array.push is not a function

// push は Array.prototype のメソッド(インスタンスメソッド)
// Array 自体(コンストラクタ関数)には push メソッドは存在しない
修正後のコード
// 配列インスタンスに対して push を呼ぶ
const arr = [];
arr.push(1);
console.log(arr);  // [1]

// 静的メソッドの例(Array に直接呼べるもの)
Array.isArray([]);      // true
Array.from("abc");  // ["a", "b", "c"]

this のコンテキスト消失

メソッドを変数に代入したり、コールバックとして渡すと this のコンテキストが失われ、メソッド内で this.xxxundefined になることがあります。

Uncaught TypeError: this.getName is not a function

エラーが出るコード
const user = {
  name: "Alice",
  getName() { return this.name; },
  greet() {
    // setTimeout のコールバック内で this が変わる
    setTimeout(function() {
      console.log(this.getName());
      // TypeError: this.getName is not a function
      // this は window(またはundefined)を指している
    }, 1000);
  }
};
user.greet();
修正方法1: アロー関数を使う
const user = {
  name: "Alice",
  getName() { return this.name; },
  greet() {
    // アロー関数は外側の this を引き継ぐ
    setTimeout(() => {
      console.log(this.getName());
      // "Alice" ← 正常動作
    }, 1000);
  }
};
user.greet();
修正方法2: bind を使う
const user = {
  name: "Alice",
  getName() { return this.name; },
  greet() {
    setTimeout(function() {
      console.log(this.getName());
    }.bind(this), 1000);
  }
};
user.greet();  // "Alice"

メソッドを変数に取り出して呼び出すパターン

オブジェクトからメソッドを取り出して別の変数に代入すると、this の参照先が変わります。

Uncaught TypeError: Cannot read properties of undefined (reading "length")

エラーが出るコード
const calculator = {
  values: [1, 2, 3],
  sum() {
    return this.values.reduce((a, b) => a + b, 0);
  }
};

// メソッドを変数に取り出す
const sumFn = calculator.sum;
sumFn();  // TypeError: Cannot read properties of undefined
// this.values が undefined になる
修正後のコード
// 方法1: bind でコンテキストを固定
const sumFn = calculator.sum.bind(calculator);
sumFn();  // 6

// 方法2: オブジェクト経由で呼び出す
calculator.sum();  // 6

配列メソッドの誤用

配列メソッド(map, filter, forEach, reduce など)は配列(Array)のインスタンスメソッドです。配列でないものにこれらのメソッドを使うと「is not a function」エラーが発生します。

配列でないものに配列メソッドを使った

オブジェクトや文字列に対して配列メソッドを呼び出すパターンです。

Uncaught TypeError: data.map is not a function

エラーが出るコード
// オブジェクトに map を使おうとする
const data = { a: 1, b: 2, c: 3 };
data.map(item => item * 2);
// TypeError: data.map is not a function

// 文字列に forEach を使おうとする
const str = "hello";
str.forEach(char => console.log(char));
// TypeError: str.forEach is not a function
修正後のコード
// オブジェクトの場合: Object.keys / Object.values / Object.entries を使う
const data = { a: 1, b: 2, c: 3 };

// 値の配列に変換してから map
Object.values(data).map(item => item * 2);
// [2, 4, 6]

// キーと値のペアで処理
Object.entries(data).forEach(([key, val]) => {
  console.log(key, val);
});

// 文字列の場合: split で配列にするか、for...of を使う
const str = "hello";
str.split("").forEach(char => console.log(char));
// h, e, l, l, o

// for...of でも可
for (const char of str) {
  console.log(char);
}

querySelectorAll の戻り値に配列メソッドを使った

querySelectorAllNodeListを返します。NodeList は配列に似ていますが、mapfilter などの配列メソッドは使えません(forEach は使えます)。

Uncaught TypeError: elements.map is not a function

エラーが出るコード
const elements = document.querySelectorAll(".item");

// NodeList には map メソッドがない
elements.map(el => el.textContent);
// TypeError: elements.map is not a function
修正後のコード
const elements = document.querySelectorAll(".item");

// 方法1: Array.from() で配列に変換
Array.from(elements).map(el => el.textContent);

// 方法2: スプレッド構文で配列に変換
[...elements].map(el => el.textContent);

// 方法3: forEach は NodeList でも使える
elements.forEach(el => {
  console.log(el.textContent);
});

arguments オブジェクトに配列メソッドを使った

関数内の arguments オブジェクトは配列風(array-like)ですが、配列ではありません。

Uncaught TypeError: arguments.map is not a function

エラーが出るコード
function sumAll() {
  // arguments は配列風オブジェクト(Array-like)
  return arguments.reduce((a, b) => a + b, 0);
  // TypeError: arguments.reduce is not a function
}
sumAll(1, 2, 3);
修正後のコード
// 方法1: Array.from() で変換
function sumAll() {
  return Array.from(arguments).reduce((a, b) => a + b, 0);
}

// 方法2: スプレッド構文で変換
function sumAll2() {
  return [...arguments].reduce((a, b) => a + b, 0);
}

// 方法3: 最初からレストパラメータを使う(推奨)
function sumAll3(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}

console.log(sumAll3(1, 2, 3));  // 6

ポイント:ES6以降では arguments の代わりにレストパラメータ(…args)を使うのが推奨です。レストパラメータは本物の配列なので、配列メソッドがそのまま使えます。

API レスポンスが期待と異なる型だった

API から取得したデータが配列ではなくオブジェクトだった場合に頻発するパターンです。

Uncaught TypeError: response.data.map is not a function

エラーが出るコード
// API レスポンスがオブジェクトで返ってきた場合
const response = {
  data: {
    users: ["Alice", "Bob"],
    total: 2
  }
};

// data はオブジェクトなので map は使えない
response.data.map(item => item);
// TypeError: response.data.map is not a function
修正後のコード
// 正しいプロパティ(配列)にアクセスする
response.data.users.map(item => item);
// ["Alice", "Bob"]

// 安全にアクセスする(型チェック付き)
const items = Array.isArray(response.data)
  ? response.data
  : response.data.users || [];
items.map(item => item);

コールバック関数でのエラー

コールバック関数に関連する「is not a function」エラーは、関数を渡すべき場所に関数以外の値を渡してしまうことで発生します。

undefined をコールバックとして渡した

変数が未定義(undefined)の状態でコールバックとして渡すと、呼び出し時にエラーが発生します。

Uncaught TypeError: callback is not a function

エラーが出るコード
function fetchData(url, callback) {
  // データ取得後にコールバックを呼び出す
  const data = { result: "success" };
  callback(data);  // TypeError: callback is not a function
}

// コールバックを渡し忘れた
fetchData("/api/users");
修正後のコード
function fetchData(url, callback) {
  const data = { result: "success" };

  // 方法1: コールバックが関数かチェックしてから呼ぶ
  if (typeof callback === "function") {
    callback(data);
  }
}

// 方法2: デフォルト引数を使う
function fetchData2(url, callback = () => {}) {
  const data = { result: "success" };
  callback(data);
}

// コールバックなしでも呼べる
fetchData2("/api/users");

// コールバック付きでも呼べる
fetchData2("/api/users", (data) => {
  console.log(data);
});

関数の戻り値をコールバックとして渡した(func() vs func)

関数を渡すべき場所で、関数の実行結果を渡してしまうパターンです。func(関数への参照)と func()(関数の実行結果)の違いに注意が必要です。

Uncaught TypeError: callback is not a function

エラーが出るコード
function handleClick() {
  console.log("クリックされました");
}

// handleClick() ← 実行結果(undefined)を渡している
document.addEventListener("click", handleClick());
// addEventListener の第2引数が undefined になる

// 同様のミス:
setTimeout(handleClick(), 1000);
// TypeError: callback is not a function
修正後のコード
function handleClick() {
  console.log("クリックされました");
}

// handleClick ← () を付けず関数への参照を渡す
document.addEventListener("click", handleClick);

// setTimeout も同様
setTimeout(handleClick, 1000);

// 引数を渡したい場合はアロー関数でラップ
setTimeout(() => handleClick("引数"), 1000);

ポイント:func は関数オブジェクトへの参照(渡す)、func() は関数を実行した戻り値(実行する)です。コールバックには () を付けない func を渡します。

addEventListener での問題

addEventListener の第2引数に関数以外を渡すとエラーになります。また、イベント名のタイポにも注意が必要です。

Uncaught TypeError: Failed to execute "addEventListener": parameter 2 is not of type "Object"

エラーが出るパターン集
const btn = document.getElementById("myBtn");

// パターン1: 関数の実行結果を渡している
btn.addEventListener("click", handleClick());

// パターン2: 文字列を渡している
btn.addEventListener("click", "handleClick");

// パターン3: null を渡している
let handler = null;
btn.addEventListener("click", handler);
修正後のコード
const btn = document.getElementById("myBtn");

// 関数への参照を渡す
btn.addEventListener("click", handleClick);

// アロー関数でインラインに書く
btn.addEventListener("click", (event) => {
  console.log("クリック!", event.target);
});

配列メソッドのコールバックが undefined

map や filter のコールバック引数に undefined を渡すとエラーになります。

Uncaught TypeError: undefined is not a function

エラーが出るコード
const numbers = [1, 2, 3];

// 変数が定義されていない関数を参照
let transformer;
numbers.map(transformer);
// TypeError: undefined is not a function
修正後のコード
const numbers = [1, 2, 3];

// 関数を正しく定義してから渡す
const transformer = (n) => n * 2;
numbers.map(transformer);
// [2, 4, 6]

// または直接アロー関数を渡す
numbers.map(n => n * 2);

DOM操作でのエラー

DOM操作で「is not a function」が発生するパターンは、要素が見つからない(null が返る)、スクリプトの実行タイミングが早い、HTMLCollection と NodeList の扱いの違いなどが原因です。

querySelector が null を返す場合

querySelectorgetElementById で要素が見つからない場合、null が返ります。null に対してメソッドを呼び出すとエラーになります。

Uncaught TypeError: Cannot read properties of null (reading "addEventListener")

エラーが出るコード
// 存在しないIDを指定
const btn = document.getElementById("submitBtn");
// btn は null(要素が見つからなかった)

btn.addEventListener("click", () => {
  console.log("クリック");
});
// TypeError: Cannot read properties of null
修正後のコード
// 方法1: null チェックを行う
const btn = document.getElementById("submitBtn");
if (btn) {
  btn.addEventListener("click", () => {
    console.log("クリック");
  });
}

// 方法2: Optional chaining(?.)を使う
document.getElementById("submitBtn")?.addEventListener("click", () => {
  console.log("クリック");
});

DOMContentLoaded 前にスクリプトが実行される

HTMLの読み込みが完了する前にJavaScriptが実行されると、まだ存在しない要素にアクセスしようとしてエラーになります。

Uncaught TypeError: Cannot read properties of null (reading "textContent")

エラーが出るコード(HTML)
<head>
  <script src="app.js"></script>
  <!-- body の要素がまだ読み込まれていない状態で app.js が実行される -->
</head>
<body>
  <h1 id="title">Hello</h1>
</body>
app.js(エラーが出る)
// この時点では #title はまだ存在しない
const title = document.getElementById("title");
console.log(title.textContent);
// TypeError: Cannot read properties of null
修正方法1: DOMContentLoaded イベントを使う
document.addEventListener("DOMContentLoaded", () => {
  const title = document.getElementById("title");
  console.log(title.textContent);  // "Hello"
});
修正方法2: script タグを body の末尾に置く
<body>
  <h1 id="title">Hello</h1>
  <!-- body の末尾に script を置く -->
  <script src="app.js"></script>
</body>
修正方法3: defer 属性を使う
<head>
  <!-- defer: HTMLの解析完了後に実行 -->
  <script src="app.js" defer></script>
</head>

HTMLCollection と NodeList の違い

getElementsByClassNamegetElementsByTagNameHTMLCollectionを返します。HTMLCollection は forEach メソッドを持っていません。

Uncaught TypeError: items.forEach is not a function

エラーが出るコード
// getElementsByClassName は HTMLCollection を返す
const items = document.getElementsByClassName("item");

// HTMLCollection には forEach がない
items.forEach(item => {
  console.log(item.textContent);
});
// TypeError: items.forEach is not a function
修正後のコード
// 方法1: Array.from() で変換
const items = document.getElementsByClassName("item");
Array.from(items).forEach(item => {
  console.log(item.textContent);
});

// 方法2: スプレッド構文
[...items].forEach(item => {
  console.log(item.textContent);
});

// 方法3: querySelectorAll を使う(NodeList は forEach を持つ)
const items2 = document.querySelectorAll(".item");
items2.forEach(item => {
  console.log(item.textContent);
});
メソッド 戻り値 forEach map / filter
querySelectorAll NodeList 使える 使えない
getElementsByClassName HTMLCollection 使えない 使えない
getElementsByTagName HTMLCollection 使えない 使えない
querySelector Element / null
getElementById Element / null

非同期処理でのエラー

Promise、async/await、fetch、setTimeout などの非同期処理で「is not a function」が発生するパターンを解説します。

Promise の then / catch が関数でない

thencatch に渡す引数は関数でなければなりません。

Uncaught TypeError: "Success" is not a function

エラーが出るコード
const promise = new Promise((resolve) => {
  resolve("data");
});

// then に文字列を渡している
promise.then("Success");
// 文字列は関数ではないのでエラー
修正後のコード
const promise = new Promise((resolve) => {
  resolve("data");
});

// 関数を渡す
promise.then((data) => {
  console.log("Success:", data);
});

async/await での誤用

await の対象が関数でなかったり、async 関数の呼び出し方を間違えるパターンです。

Uncaught TypeError: fetchUsers is not a function

エラーが出るコード
// async 関数を変数に代入し、別の値で上書き
let fetchUsers = async () => {
  const res = await fetch("/api/users");
  return res.json();
};

// 実行結果で上書きしてしまう
fetchUsers = await fetchUsers();

// 2回目の呼び出しでエラー
const users = await fetchUsers();
// TypeError: fetchUsers is not a function
修正後のコード
// const で関数を保護する
const fetchUsers = async () => {
  const res = await fetch("/api/users");
  return res.json();
};

// 結果は別の変数に格納
const users = await fetchUsers();
console.log(users);

fetch のレスポンス処理ミス

fetch API のレスポンスオブジェクトの扱いを間違えるパターンです。

Uncaught TypeError: data.json is not a function

エラーが出るコード
const response = await fetch("/api/data");
const data = await response.json();

// data はすでに JSON オブジェクト(.json() 済み)
const parsed = data.json();
// TypeError: data.json is not a function
// .json() は Response オブジェクトのメソッド
// data は通常のオブジェクトなので .json() はない
修正後のコード
// .json() は Response オブジェクトに1回だけ使う
const response = await fetch("/api/data");
const data = await response.json();

// data はそのまま使える(もう JavaScript オブジェクト)
console.log(data);

// もし文字列に変換したい場合は JSON.stringify を使う
const jsonStr = JSON.stringify(data);
console.log(jsonStr);

setTimeout / setInterval の引数ミス

第1引数に関数ではなく文字列や実行結果を渡すとエラーになります。

Uncaught TypeError: callback is not a function(内部エラー)

エラーが出るコード
// 関数の実行結果を渡している
setTimeout(doSomething(), 1000);
// doSomething() の戻り値(undefined)が渡される

// 文字列を渡している(非推奨で動作するがセキュリティリスク)
setTimeout("doSomething()", 1000);
修正後のコード
// 関数への参照を渡す(() を付けない)
setTimeout(doSomething, 1000);

// 引数を渡したい場合
setTimeout(() => doSomething("arg1", "arg2"), 1000);

// または第3引数以降で渡す
setTimeout(doSomething, 1000, "arg1", "arg2");

外部ライブラリ・モジュールでのエラー

外部ライブラリやモジュールに関連する「is not a function」エラーは、読み込み順序、CDNの失敗、import/export の不一致などが原因です。

ライブラリの読み込み順序

ライブラリを使うスクリプトより後にライブラリを読み込むと、ライブラリの関数が undefined になります。

Uncaught TypeError: $ is not a function

エラーが出るコード(HTML)
<!-- 先にアプリのスクリプトを読み込んでいる -->
<script src="app.js"></script>
<!-- jQuery が後に読み込まれる → app.js 実行時に $ は未定義 -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
修正後のコード(HTML)
<!-- 先にライブラリを読み込む -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- 次にアプリのスクリプト -->
<script src="app.js"></script>

CDN の読み込み失敗

CDNからの読み込みが失敗すると、ライブラリの関数が利用できずエラーになります。

CDN失敗時のフォールバック
<script src="https://cdn.example.com/lib.js"></script>
<script>
// CDN が失敗した場合のフォールバック
if (typeof MyLib === "undefined") {
  console.warn("CDN失敗。ローカルから読み込みます");
  const script = document.createElement("script");
  script.src = "/js/lib.js";
  document.head.appendChild(script);
}
</script>

import / require のミス(default export vs named export)

ES Modules の import で default export と named export を間違えると、このエラーが頻発します。

Uncaught TypeError: (0, myModule.default) is not a function

エラーが出るコード
// utils.js - named export で定義
export function formatDate(date) {
  return date.toISOString();
}

// app.js - default import しようとする(間違い)
import formatDate from "./utils.js";
formatDate(new Date());
// TypeError: formatDate is not a function
// default export がないため、formatDate は undefined
修正後のコード
// named export には中括弧 {{}} を使う
import { formatDate } from "./utils.js";
formatDate(new Date());  // 正常動作

// または default export で定義する場合
// utils.js
export default function formatDate(date) {
  return date.toISOString();
}

// app.js - default import
import formatDate from "./utils.js";
formatDate(new Date());  // 正常動作
export の種類 import の書き方 間違いやすいパターン
export default fn import fn from "..." import { fn } from "..." → undefined
export function fn import { fn } from "..." import fn from "..." → undefined
module.exports = fn const fn = require("...") const { fn } = require("...") → undefined
exports.fn = fn const { fn } = require("...") const fn = require("...") → object

jQuery の $ が未定義

jQueryが読み込まれていない、またはnoConflictモードで$が使えない場合に発生します。

Uncaught TypeError: $ is not a function

エラーが出るパターンと修正
// パターン1: jQuery が読み込まれていない
// → jQuery のスクリプトタグを確認する

// パターン2: WordPress の noConflict モード
// WordPress では jQuery が noConflict() で読み込まれる
// $ の代わりに jQuery を使う
jQuery(document).ready(function($) {
  // この中では $ が使える
  $(".menu").toggle();
});

// または即時関数で $ を受け取る
(function($) {
  $(".menu").toggle();
})(jQuery);

ライブラリのバージョン違い

ライブラリのバージョンアップでAPIが変更された場合、以前のメソッドが削除されてエラーになることがあります。

バージョン違いの例
// Lodash 3.x → 4.x で名前が変わったメソッド
// _.contains() → _.includes()
_.contains([1,2,3], 2);
// TypeError: _.contains is not a function(Lodash 4.x)

// 修正: 新しいメソッド名を使う
_.includes([1,2,3], 2);  // true

ポイント:ライブラリをアップデートした後にエラーが出た場合は、マイグレーションガイドやリリースノートを確認して、APIの変更点をチェックしましょう。

クラス・コンストラクタでのエラー

ES6のクラス構文を使う際に「is not a function」が発生するパターンを解説します。new の忘れ、static メソッドとインスタンスメソッドの混同、継承時の問題などがあります。

new を忘れた場合

クラスは new キーワードなしでは呼び出せません。

Uncaught TypeError: Class constructor User cannot be invoked without "new"

エラーが出るコード
class User {
  constructor(name) {
    this.name = name;
  }
}

// new を忘れている
const user = User("Alice");
// TypeError: Class constructor User cannot be invoked without "new"
修正後のコード
class User {
  constructor(name) {
    this.name = name;
  }
}

// new を付けてインスタンス化する
const user = new User("Alice");
console.log(user.name);  // "Alice"

static メソッドとインスタンスメソッドの混同

static メソッドはクラス自体から呼び出し、インスタンスメソッドはインスタンスから呼び出します。混同するとエラーになります。

Uncaught TypeError: user.create is not a function

エラーが出るコード
class User {
  constructor(name) {
    this.name = name;
  }

  // static メソッド(クラスに属する)
  static create(name) {
    return new User(name);
  }

  // インスタンスメソッド(インスタンスに属する)
  greet() {
    return "Hello, " + this.name;
  }
}

const user = new User("Alice");

// static メソッドをインスタンスから呼ぶ → エラー
user.create("Bob");
// TypeError: user.create is not a function

// インスタンスメソッドをクラスから呼ぶ → エラー
User.greet();
// TypeError: User.greet is not a function
修正後のコード
// static メソッドはクラスから呼ぶ
const bob = User.create("Bob");
console.log(bob.name);  // "Bob"

// インスタンスメソッドはインスタンスから呼ぶ
const user = new User("Alice");
console.log(user.greet());  // "Hello, Alice"
メソッドの種類 定義方法 呼び出し方
インスタンスメソッド greet() { ... } instance.greet()
static メソッド static create() { ... } ClassName.create()

継承時の super 呼び出しミス

子クラスの constructor で super() を呼ぶ前に this を使うとエラーになります。

Uncaught ReferenceError: Must call super constructor in derived class before accessing "this"

エラーが出るコード
class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    // super() を呼ぶ前に this を使っている
    this.breed = breed;  // ReferenceError!
    super(name);
  }
}
修正後のコード
class Dog extends Animal {
  constructor(name, breed) {
    // 必ず最初に super() を呼ぶ
    super(name);
    this.breed = breed;
  }
}

const dog = new Dog("Pochi", "Shiba");
console.log(dog.name);   // "Pochi"
console.log(dog.breed);  // "Shiba"

private メソッドへのアクセス

ES2022 で導入された # プレフィックス付きのプライベートメソッド/プロパティは、クラス外部からアクセスできません。

Uncaught TypeError: Cannot read private member #validate from an object whose class did not declare it

エラーが出るコード
class FormValidator {
  // プライベートメソッド
  #validate(input) {
    return input.length > 0;
  }

  check(input) {
    return this.#validate(input);
  }
}

const validator = new FormValidator();
validator.check("test");     // true ← OK
validator.#validate("test");  // SyntaxError!
修正後のコード
// プライベートメソッドには公開メソッド経由でアクセスする
const validator = new FormValidator();
console.log(validator.check("test"));  // true

// プライベートメソッドを外部に公開したい場合は、
// # を外して通常のメソッドにする
class FormValidator2 {
  validate(input) {
    return input.length > 0;
  }
}

デバッグテクニック

「is not a function」エラーを素早く解決するためのデバッグテクニックを紹介します。

typeof でチェックする

エラーが発生する箇所の直前で typeof を使って値の型を確認しましょう。

typeof でデバッグ
// エラーが発生する関数呼び出しの前に型をチェック
function executeCallback(cb) {
  console.log("typeof cb:", typeof cb);
  console.log("cb の値:", cb);

  if (typeof cb !== "function") {
    console.error("cb は関数ではありません:", cb);
    return;
  }
  cb();
}

console.log で確認する

エラーが発生する変数の中身を console.log で出力して確認します。

console.log でステップバイステップ確認
const obj = getApiResponse();
console.log("1. obj:", obj);
console.log("2. obj.data:", obj.data);
console.log("3. typeof obj.data:", typeof obj.data);
console.log("4. Array.isArray:", Array.isArray(obj.data));

// ここでエラーが出る場合、上の出力を見て原因を特定
obj.data.map(item => item);

try-catch で安全に呼び出す

本番環境では、関数呼び出しを try-catch で囲んでエラーを捕捉できます。

try-catch パターン
function safeCall(fn, ...args) {
  try {
    if (typeof fn !== "function") {
      throw new TypeError(`${fn.name || fn} is not a function`);
    }
    return fn(...args);
  } catch (error) {
    console.error("関数呼び出しエラー:", error.message);
    return null;
  }
}

// 使い方
safeCall(myCallback, "arg1", "arg2");

Optional chaining(?.)の活用

ES2020 の Optional chaining を使うと、null/undefined チェックを簡潔に書けます。

Optional chaining の活用
// 従来の書き方(冗長)
if (obj && obj.method && typeof obj.method === "function") {
  obj.method();
}

// Optional chaining を使う(簡潔)
obj?.method?.();  // obj や method が null/undefined なら undefined を返す

// DOM 操作での活用
document.querySelector("#btn")?.addEventListener("click", handler);

// コールバックの安全な呼び出し
function fetchData(url, onSuccess, onError) {
  fetch(url)
    .then(res => res.json())
    .then(data => onSuccess?.(data))
    .catch(err => onError?.(err));
}

ブラウザデベロッパーツールの使い方

ブラウザのデベロッパーツールには、エラーのデバッグに役立つ機能が多数あります。

機能 使い方 役立つ場面
Console タブ F12 → Console エラーメッセージとスタックトレースの確認
Sources タブ F12 → Sources → ブレークポイント設置 実行を一時停止して変数の値を確認
Pause on exceptions Sources タブの ⏸ アイコン エラー発生時に自動で一時停止
Watch 式 Sources → Watch に式を追加 特定の変数の値を監視
Call Stack ブレークポイントで停止中に確認 どの関数から呼ばれたかを追跡
デバッガーを使ったデバッグ
// コード中に debugger 文を挿入すると
// DevTools が開いている場合、その行で実行が一時停止する
function processData(callback) {
  debugger;  // ここで一時停止
  // DevTools で callback の値を確認できる
  callback(data);
}

実務でよくあるパターン10選

実際の開発現場で遭遇しやすい「is not a function」エラーのパターンを厳選して紹介します。

パターン1: getElementById().addEventListener() で null

Uncaught TypeError: Cannot read properties of null (reading "addEventListener")

問題と解決
// 問題: 要素が見つからない
document.getElementById("nonExistent").addEventListener("click", fn);

// 解決: null チェック + Optional chaining
const el = document.getElementById("myElement");
if (el) {
  el.addEventListener("click", fn);
}
// または
document.getElementById("myElement")?.addEventListener("click", fn);

パターン2: JSON.parse の結果にメソッド呼び出し

Uncaught TypeError: data.getFullYear is not a function

問題と解決
// 問題: JSON.parse した日付文字列を Date として扱おうとする
const json = '{{"created":"2024-01-15"}}';
const data = JSON.parse(json);
data.created.getFullYear();
// TypeError: data.created.getFullYear is not a function
// data.created は文字列であり、Date オブジェクトではない

// 解決: Date オブジェクトに変換する
const date = new Date(data.created);
console.log(date.getFullYear());  // 2024

パターン3: map / filter をオブジェクトに使う

Uncaught TypeError: config.map is not a function

問題と解決
// 問題: オブジェクトに map を使おうとする
const config = { host: "localhost", port: 3000 };
config.map((key, val) => ...);

// 解決: Object.entries() を使う
Object.entries(config).map(([key, val]) => {
  console.log(`${key}: ${val}`);
});

パターン4: String / Number のメソッド名タイポ

Uncaught TypeError: str.touppercase is not a function

問題と解決
const str = "hello";

// 問題: キャメルケースの大文字小文字ミス
str.touppercase();   // TypeError
str.toUppercase();   // TypeError

// 解決: 正しいキャメルケース
str.toUpperCase();   // "HELLO"
str.toLowerCase();   // "hello"
str.replaceAll("l", "r");  // "herro"

パターン5: window.onload の二重定義

2番目のonloadハンドラが1番目を上書きする

問題と解決
// 問題: 2番目の代入が1番目を上書きする
window.onload = function() {
  console.log("1番目の処理");
};

window.onload = function() {
  console.log("2番目の処理");
  // 1番目の処理は実行されない!
};

// 解決: addEventListener を使う
window.addEventListener("load", () => {
  console.log("1番目の処理");
});
window.addEventListener("load", () => {
  console.log("2番目の処理");
  // 両方とも実行される
});

パターン6: forEach の戻り値を使おうとする

Uncaught TypeError: Cannot read properties of undefined

問題と解決
// 問題: forEach は undefined を返す
const result = [1,2,3].forEach(n => n * 2);
console.log(result);  // undefined
result.join(", ");  // TypeError!

// 解決: 変換したい場合は map を使う
const result2 = [1,2,3].map(n => n * 2);
console.log(result2.join(", "));  // "2, 4, 6"

パターン7: Promise を await し忘れる

Uncaught TypeError: response.map is not a function

問題と解決
// 問題: await を付け忘れている
async function getUsers() {
  const response = fetch("/api/users");  // await がない!
  // response は Promise オブジェクト(Response ではない)
  const data = response.json();
  // TypeError: response.json is not a function
}

// 解決: await を付ける
async function getUsers() {
  const response = await fetch("/api/users");
  const data = await response.json();
  return data;
}

パターン8: 分割代入で関数を壊す

Uncaught TypeError: greet is not a function

問題と解決
// 問題: 分割代入で意図しない値を取得
const module = {
  greet() { return "Hello"; },
  version: "1.0"
};

// default という名前で分割代入しようとする
const { default: greet } = module;
// module.default は undefined → greet も undefined
greet();  // TypeError: greet is not a function

// 解決: 正しいプロパティ名で分割代入
const { greet } = module;
greet();  // "Hello"

パターン9: reduce の初期値を忘れる

Uncaught TypeError: Cannot read properties of undefined

問題と解決
// 問題: 空配列に reduce を使い、初期値がない
const items = [];
items.reduce((sum, item) => sum + item.price);
// TypeError: Reduce of empty array with no initial value

// 解決: 初期値を必ず渡す
const total = items.reduce((sum, item) => sum + item.price, 0);
console.log(total);  // 0

パターン10: チェーン中の null

Uncaught TypeError: Cannot read properties of null

問題と解決
// 問題: チェーンの途中で null が返る
document
  .querySelector(".container")
  .querySelector(".title")
  .textContent;
// .container が存在しない → null.querySelector() でエラー

// 解決: Optional chaining でチェーンを安全にする
const title = document
  .querySelector(".container")
  ?.querySelector(".title")
  ?.textContent;

console.log(title ?? "要素が見つかりません");

まとめ

この記事では、JavaScriptの「TypeError: X is not a function」エラーについて、発生する原因と解決方法を網羅的に解説しました。

「is not a function」解決フローチャート

エラーに遭遇したら、以下の順序で原因を調査してください。

解決の手順

  1. エラーメッセージを読む:「is not a function」の前の名前を確認
  2. typeof で型を確認:その変数の型は何か?(console.log(typeof xxx)
  3. undefined の場合:変数が正しく定義・代入されているか確認
  4. 別の型の場合:変数名の衝突がないか、メソッド名のタイポがないか確認
  5. スタックトレースを確認:エラーが発生したファイルと行番号を確認
  6. 実行タイミングを確認:DOM要素にアクセスする場合、DOMContentLoaded後か確認
  7. 外部ライブラリを確認:読み込み順序、CDNの可用性、バージョンを確認

関連エラーとの違い

「is not a function」と似たエラーメッセージがいくつかあります。それぞれの違いを理解しておきましょう。

エラーメッセージ 原因
TypeError: X is not a function 関数でないものを()で呼び出した undefined()
ReferenceError: X is not defined 変数自体が宣言されていない foo() ※fooが未宣言
TypeError: Cannot read properties of null nullのプロパティにアクセスした null.method()
TypeError: Cannot read properties of undefined undefinedのプロパティにアクセスした undefined.method()
TypeError: X is not a constructor コンストラクタでないものをnewした new 42()

予防のためのベストプラクティス

エラーを予防する7つの習慣

  1. const を使う:変数の再代入を防ぎ、関数が意図せず上書きされるのを防止
  2. 明確な命名規則:関数は動詞で始める(getData)、変数は名詞(userData
  3. typeof チェック:コールバックを受け取る関数では typeof callback === "function" でチェック
  4. Optional chaining(?.):null/undefined の可能性がある値には ?. を使う
  5. ESLint を使う:未使用変数やタイポを静的解析で検出
  6. TypeScript の導入:型チェックにより、関数でない値の呼び出しをコンパイル時に検出
  7. テストを書く:関数の入出力をテストして、想定外の値が渡されるケースを検証

「is not a function」エラーは、原因が分かれば素早く修正できるエラーです。この記事で紹介したパターンを参考に、エラーに遭遇した際はまずtypeof で変数の型を確認し、スタックトレースでエラーの発生箇所を特定するようにしましょう。