「thisパラメータを明示する」とは何をしているのか
まず言葉の整理からいきます。
TypeScript でいう「thisパラメータ」とは、
関数の一番最初の引数の位置にだけ書ける、特別な仮引数のことです。
function greet(this: { name: string }) {
console.log(`Hello, ${this.name}`);
}
TypeScriptここでの this: { name: string } は、
「この関数の中で使われる this は { name: string } 型ですよ」
という宣言だけです。
実際の呼び出し時に this を引数として渡すわけではありません。this はあくまで call / apply / メソッド呼び出しなどでバインドされます。
thisパラメータを明示する=この関数が前提としている「文脈(コンテキスト)」を型で宣言すること
と捉えてください。
基本形:thisパラメータの書き方と呼び出し方
thisパラメータ付き関数の定義
最小の例からいきます。
function showName(this: { name: string }) {
console.log(this.name);
}
TypeScriptこの関数の中では、this は必ず { name: string } 型として扱われます。
function showName(this: { name: string }) {
// this: { name: string }
console.log(this.name.toUpperCase()); // OK
}
TypeScriptthis に name がない前提のコードは書けません。
逆に言うと、「name がある前提で安心して書ける」ということです。
thisをバインドして呼び出す
呼び出し側は call / apply / bind などで this を指定します。
const person = { name: "Taro" };
showName.call(person); // Hello, Taro
TypeScriptここで TypeScript は、
showName は「this: { name: string }」を前提にしているcall に渡された person が { name: string } を満たしているか
をチェックします。
もし足りないプロパティのオブジェクトを渡すと、コンパイルエラーになります。
const obj = { title: "Book" };
// showName.call(obj); // エラー: '{ title: string }' に 'name' がない
TypeScriptどんなときに thisパラメータを「明示すべき」か
1. this に強く依存する「自由関数」を書くとき
クラスのメソッドではなく、単体の関数として this に依存する処理を書くときは、
thisパラメータを明示した方が圧倒的に安全です。
function increment(this: { value: number }) {
this.value++;
}
TypeScriptこの関数は、「value: number を持つオブジェクトにバインドされること」を前提にしています。
const counter = { value: 0 };
increment.call(counter);
console.log(counter.value); // 1
TypeScriptここでの重要ポイントは、
「this に依存する自由関数を書いたのに、this の型を明示しないと、
どんなオブジェクトでもバインドできてしまい、バグの温床になる」
ということです。
this: { value: number } を明示することで、
「この関数は value を持たないオブジェクトには使えない」という制約を
コンパイル時にかけられます。
2. オブジェクトリテラルのメソッドで this を厳密にしたいとき
オブジェクトリテラルのメソッドでも thisパラメータは使えます。
const counter = {
value: 0,
increment(this: { value: number }) {
this.value++;
},
};
TypeScriptこの書き方の意味は、
「increment の中の this は { value: number } である」
「このメソッドを他のオブジェクトにバインドして使うときも、その前提を守れ」
という宣言です。
例えば、increment を別のオブジェクトに借りて使うとき。
const another = { value: 10 };
counter.increment.call(another); // OK
TypeScriptanother に value: number があるのでOKですが、value がないオブジェクトを渡すとエラーになります。
const bad = { count: 0 };
// counter.increment.call(bad); // エラー: 'value' がない
TypeScript「このメソッドは、こういう形のオブジェクトにバインドされる前提で書いている」
というのを、型としてはっきりさせるために thisパラメータを明示します。
3. ライブラリ的な「ユーティリティ関数」を this ベースで設計するとき
例えば、Array.prototype 風の関数を this ベースで書くとします。
function first<T>(this: T[]): T | undefined {
return this[0];
}
const arr = [1, 2, 3];
first.call(arr); // 1
TypeScriptここでは、
this: T[] と書くことで、「配列にバインドされる前提の関数」であることを宣言しています。
このパターンは、
「既存のオブジェクトにメソッド風の関数を後付けしたい」
「プロトタイプ拡張風のユーティリティを this ベースで書きたい」
といったときに使えます。
thisパラメータを明示しないと、first.call({}) のような無茶な呼び出しも通ってしまうので、
「this を前提にした設計をするなら、型で縛る」という意識が大事です。
逆に「this: void」を明示すべき場面
this を絶対に使わせたくない関数
TypeScript には、こんな書き方もあります。
function log(this: void, message: string) {
console.log(message);
}
TypeScriptthis: void と書くと、
「この関数は this に依存しない」
「this をバインドして呼んではいけない」
という意味になります。
const obj = { prefix: "[X]" };
// log.call(obj, "hello"); // エラー: this は void でなければならない
log("hello"); // OK
TypeScriptここでの重要ポイントは、
「this を使わないことを、あえて型で宣言する」 という発想です。
「この関数は純粋な関数として設計したい」
「this に依存するような使い方を禁止したい」
というときに、this: void を明示しておくと、
将来の自分や他の開発者が call / apply で変な使い方をするのを防げます。
thisパラメータとアロー関数の関係
アロー関数には thisパラメータを書けない
ここは設計上かなり重要です。
// これは OK
function f(this: { value: number }) {
this.value++;
}
// これは NG(コンパイルエラー)
const g = (this: { value: number }) => {
// ...
};
TypeScriptアロー関数は「自分自身の this を持たず、外側の this をキャプチャする」仕様なので、
TypeScript でも thisパラメータを宣言できません。
この事実から、設計の指針が1つ見えてきます。
this に依存する関数を書きたいなら:
普通の function / メソッド構文+thisパラメータを使う
this に依存させたくない関数を書きたいなら:
アロー関数+(必要なら)this: void を使う
「this を使うかどうか」で、関数の書き方を意識的に選ぶ
というのが、TypeScript での関数設計のコツです。
まとめ:thisパラメータの明示を自分の言葉で言うと
最後に、あなた自身の言葉でこう整理してみてください。
thisパラメータを明示するとは、
「この関数は、こういう形の this を前提に書かれている」
「あるいは、this を一切使わない(this: void)」
ということを、型として宣言すること。
特に意味があるのは、
自由関数で this に依存するとき
オブジェクトリテラルのメソッドで this の前提をはっきりさせたいとき
ユーティリティ関数を this ベースで設計するとき
this に依存させたくない関数を“純粋”として守りたいとき
コードを書くとき、
「この関数は this に依存している? 依存させたい? させたくない?」
と一度立ち止まってから、this: 型 を書くかどうかを決めてみてください。
その一呼吸で、
this は「なんとなくそこにいるやつ」から、
あなたの設計意図をきちんと表現する“型付きのコンテキスト” に変わっていきます。
