TypeError: x is not a function の原因と直し方
関数ではない値を関数として呼び出そうとしたときに出るエラーです。変数名やメソッド名のタイプミス、あるいはプロパティと勘違いした呼び出しで頻発します。
エラーメッセージの読み方
main.js:3
main.js- ファイル名
3- 行番号 — 実際にクラッシュした行
TypeError- 例外クラス — 何が起きたか。ここを検索するのが最短です
total is not a function- 内容 — 期待していたもの、または受け付けられなかったもの
このエラーが出る典型パターン
パターン1
1 const total = 5; 2 function getTotal() { return total; } 3 console.log(total ()); ^
totalは数値であって関数ではありません。呼び出した結果を得たい場合は、値を返す関数(ここではgetTotal)を呼びます。
直し方: total を getTotal にします。
パターン2
1 const cart = { items: [] }; 2 cart.addItm ("apple"); ^ 3 console.log(cart.items.length);
cartにはaddItmという名前のメソッドは存在しません。配列に追加したい場合はcart.items.pushを呼びます。
直し方: addItm を items.push にします。
パターン3
1 const config = { name: "app", describe() { return this.name; } }; 2 console.log(config.getName ()); ^
configにgetNameというメソッドは定義されていません。実際に定義されているdescribeを呼び出す必要があります。
直し方: getName を describe にします。
パターン4
1 const numbers = [3, 1, 2]; 2 numbers.short (); ^ 3 console.log(numbers);
配列を並び替えるメソッドはsortです。shortという名前のメソッドは存在しません。
直し方: short を sort にします。
パターン5
1 const str = "hello"; 2 console.log(str.toUpper ()); ^
他言語のtoUpper()の感覚で書くと起きます。JavaScriptで大文字化するメソッド名はtoUpperCaseです。
直し方: toUpper を toUpperCase にします。
よくある誤解
ReferenceErrorと混同されがちですが別物です。変数やプロパティ自体は存在するのに、その中身が関数ではないときにTypeErrorになります。存在しない名前を参照したReferenceErrorとは原因が違います。
実務での勘所
この違いが起きる理由は、JavaScriptが「名前の解決」と「呼び出し」を別の2段階で行っているためです。obj.foo()を実行するとき、まずobj.fooという式を評価してその中身を取り出し(この時点ではfooという名前が存在しなくてもオブジェクトのプロパティ探索なのでundefinedという値になるだけで例外は起きません)、次にその取り出した値を実際に呼び出そうとします。取り出した値が関数でなければ、ここで初めてTypeErrorになります。一方、宣言されていない裸の識別子(foo()のようにドットが無い呼び出し)は、名前の解決自体がその場で失敗するためReferenceErrorになります。