【TypeScript】メソッドのthisの扱い次第ではTypeScriptでエラー検知できない

メソッドでthisを用いる際にTypeScriptではエラー検知できない場合がある

コンパイルが通るが、実行時にエラーになるようなパターンが起こり得ます。
それについて記述していきます。

再現方法

class Car {
  name: string;
  gas: number;

  constructor(name: string, gas: number = 0) {
    this.name = name;
  }

  addGas(amount: number) {
    this.gas += amount;
  }
}

const car = new Car('PRIUS', 20);
car.addGas(10); 

const copyCar = {addGas: car.addGas};
copyCar.addGas(20); 

ここでは特にエラーを表す赤い波線は出ていません。
そのためコンパイルが通ります。 エラーを表す赤い波線は出ていません。

addGasメソッドを呼び出してみます。

carでは燃料追加することができましたが、copyCarではNaNと表示されてしましました。
carでは燃料追加することができましたが、copyCarではNaNと表示されてしましました。

copyCarにはgasプロパティが定義されていないからです。

メソッドでthisを用いている場合、
メソッドの前にあるオブジェクト内のプロパティやメソッドを指します。

car.addGas()だとcarオブジェクトのgasプロパティを参照し、
copyCar.addGas()だとcopyCarのgasプロパティを参照しようとします。

もちろん、copyCarにはgasプロパティは存在しない(undefined)ため
gasを追加することができずNaNになります。

対処方法

きちんとTypeScriptで検知するためには
メソッドの第1引数(※必ず第1引数にする)にthis: クラス名を入れます。

今回の例では下記のようにします。

  addGas(this: Car, amount: number) {
    this.gas += amount;
    console.log(this.gas);
  }

そうすることできちんとエラーが出現します。

copyCar.addCopyにエラーがあることを示す、赤い波線が出ています。

The 'this' context of type '{ addGas: (this: Car, amount: number) => void; }' is not assignable to method's 'this' of type 'Car'.
  Type '{ addGas: (this: Car, amount: number) => void; }' is missing the following properties from type 'Car': name, gas

type '{ addGas: (this: Car, amount: number) => void; }' の 'this' コンテキストは、type 'Car' のメソッドの 'this' に代入できません。
  タイプ '{ addGas: (this: Car, amount: number) => void; }' には、タイプ 'Car' の以下のプロパティがありません: name, gas

このことからわかるように、thisに対してCarクラスの型であることを明示してあげることでエラーを表示させることができるようになります。