thisパラメータの補足

thisパラメータがイマイチよくわからなかったのでもうちょい調べた。。

thisパラメータ

function f(this: void) {
}

下記のような関数の場合、呼び出し元(コンテキスト)によってthisの参照が変わる為、正しく動作しない場合がある。

const obj = {
  name: "Jack",
  fn() {
    console.log(`this is ${this.name}.`);
  },
};
obj.fn(); // "this is Jack."を出力
const fn = obj.fn;

fn(); // TypeError: Cannot read property 'name' of undefined

const obj2 = { fn: obj.fn };
obj2.fn(); // "this is undefined."を出力

このような場合、thisパラメータを指定すると、実行時のコンテキストのthisが想定した型でない場合にエラーを発生させる。これにより想定しない呼び出しが行われず、安全に実行ができるようになる。

const obj = {
  name: "Jack",
  fn(this: { name: string }) {
    console.log(`this is ${this.name}.`);
  },
};
obj.fn(); // "this is Jack."を出力
const fn = obj.fn;

fn(); //  error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type '{ name: string; }'.

const obj2 = { fn: obj.fn };
obj2.fn(); // error TS2684: The 'this' context of type '{ fn: (this: { name: string; }) => void; }' is not assignable to method's 'this' of type '{ name: string; }'.

this:void

また、特にコールバックは呼び出し元の違いによりエラーが発生しやすい。 この為、thisパラメータを使用して、thisを使用しない関数だけを許容するように宣言することができる。

this: void を宣言することにより、this:void以外の関数が指定された場合にエラーとする.

class Sample {
  name = "foo";
  useThis(this: Sample) {
    console.log(this.name);
  }
  notUseThis(this: void) {
    console.log("goo");
  }
}

const sample = new Sample();
// エラーが発生
// error TS2345: Argument of type '(this: Sample) => void' is not assignable to parameter of type '(this: void) => void'.
// The 'this' types of each signature are incompatible.
// Type 'void' is not assignable to type 'Sample'.
fn(sample.useThis); 

fn(sample.notUseThis); // goo を出力