はじめに
表題のエラーに遭遇したので、解決方法を探りました。
この記事は、表題の問題の詳細と解決方法を共有するためのものです。
発生環境
TypeScript 3.7.2
問題の詳細
発生した問題
コンストラクタ内で特定のアロー関数がundefinedとなります。
pen.js:32 Uncaught TypeError: this.arrow is not a function
at ExtendClass.init (pen.js:32)
at ExtendClass.BaseClass (pen.js:14)
at new ExtendClass (pen.js:24)
at pen.js:36
問題が発生する最小限のコード
class BaseClass {
constructor()
{
this.init();
}
init():void{
console.log("init Base Class");
}
}
class ExtendClass extends BaseClass{
constructor(){
super();
}
init():void{
super.init();
this.arrow();
}
arrow = () =>{
console.log("Arrow func");
}
}
const instance = new ExtendClass();
console.log( instance );
CodePenはこちらです。
問題の発生手順
問題が発生する手順は
- 基底クラスを定義する
- 基底クラスのコンストラクタ内で関数を呼び出す
- 基底クラスを継承した拡張クラスを定義する
- 拡張クラスで手順2の関数をオーバーライドする
- 手順4の関数内部でアロー関数を呼び出す
となります。
問題の原因
TypeScript Playgroundで上記のコードをJavaScriptに変換すると、以下のコードとなります。
"use strict";
class BaseClass {
constructor() {
this.init();
}
init() {
console.log("init Base Class");
}
}
class ExtendClass extends BaseClass {
constructor() {
super();
this.arrow = () => {
console.log("Arrow func");
};
}
init() {
super.init();
this.arrow();
}
}
const instance = new ExtendClass();
console.log(instance);
原因はここです。
constructor() {
super();
this.arrow = () => {
console.log("Arrow func");
};
}
アロー関数がコンストラクタの内部で宣言されています。したがってExtendClass.init
関数が実行された時点でarrow
関数はまだ定義されていません。
解決方法
アロー関数ではなく通常の関数にする
class ExtendClass extends BaseClass{
...中略...
arrow():void{
console.log("Arrow func");
}
}
アロー関数を使う必要がないなら、通常の関数に置き換えるのが最も簡単な解決方法です。
オーバーライドした関数からは呼び出さず、コンストラクタ内から呼び出す
class ExtendClass extends BaseClass{
constructor(){
super();
this.arrow();
}
arrow = () =>{
console.log("Arrow func");
}
}
設計上アロー関数でなくてはいけない場合、コンストラクタの内部で呼び出すことでこの問題を回避できます。
アロー関数は定義後に実行されます。
以上、ありがとうございました。