$ ryokkkke.com/TypeScript/tsconfig.json

noImplicitThis

概要

https://www.typescriptlang.org/tsconfig#noImplicitThis

{
  "noImplicitThis": true
}

使われているthisの型が暗黙的にanyになる場合にコンパイルエラーにします。

詳細

const func = function () {
  console.log(this);
};

このコードは、下記のコンパイルエラーが出ます。

error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

functionによる関数の場合、this の値は宣言時に定まらないため、暗黙的に型は any になるからです。

これを回避するためには 2 種類の方法があります。

1: アロー関数を使う。

アロー関数の場合、thisはそのアロー関数の定義コンテキストのthisを参照するため、定義コンテキストでthisが定まる場合で、かつそれが意図している参照なのであればアロー関数にするだけで OK です。

例えば、

const obj = {
  count: 0,
  hoge: function (label: string) {
    return function () {
      console.log(`${label}: ${this.count}`);
    };
  },
};

(実用性は何も考えないとして)上記のようにfunctionによる関数をreturnしている場合、意図としてはobj.countを参照したいが、functionではbindを使わないとthisが定まりません。
(ちなみに、仮にこの返り値の関数をbind(this)してからreturnしてもエラーは消えません)

こういう場合はアロー関数にするだけで OK。

const obj = {
  count: 0,
  hoge: function (label: string) {
    return () => {
      console.log(`${label}: ${this.count}`);
    };
  },
};

2: 明示的にthisの型を指定する。

TypeScript では、functionによる関数宣言で作られる関数の第一引数の名前がthisの場合、その引数の型は関数内のthisの型を指します。
(アロー関数にはこの機能は存在しません: 'An arrow function cannot have a 'this' parameter.ts(2730)'
そしてその場合、2 個目以降の引数が実際のその関数の引数になります。

例えば下記のような、thisconsole.logする関数があったとして、

const logThis = function () {
  console.log(this);
};

これは

error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.

が出るのでコンパイル出来ません。
しかし、この関数はアロー関数に変えても別のエラーが出ます。

error TS7041: The containing arrow function captures the global value of 'this'.

そこで、

const logThis = function (this: object) {
  console.log(this);
};

このように引数で this を指定すると、console.log(this);部分のthisは型が定まります(この場合はobject)。

この書き方をした場合は、2 個目以降の引数が実際の関数の引数になるため、呼び出しは引数を何も取らない形で実行できます。

const logThis = function (this: object) {
  console.log(`this`);
};

const obj = { logThis };

obj.logThis();

引数が欲しい場合はこう。

const logThis = function (this: object, label: string) {
  console.log(`${label}: ${this}`);
};

const obj = { logThis };

obj.logThis("HOGEHOGE:");

出力される js を見れば通常の関数として扱われているのがわかります。

var logThis = function (label) {
  console.log(label + ": " + this);
};
var obj = { logThis: logThis };
obj.logThis("HOGEHOGE");