6️⃣

[TypeScript UtilityTypes] ThisParameterType

2024/01/16に公開

TypeScript入門メモ
[Utility Types] ThisParameterType について

ThisParameterType<Type>

公式ドキュメント
https://www.typescriptlang.org/docs/handbook/utility-types.html#thisparametertypetype

関数型の this パラメータの型、または関数型に this パラメータがない場合は unknown を抽出します。

function toHex(this: Number) {
  return this.toString(16);
}
 
function numberToString(n: ThisParameterType<typeof toHex>) {
  return toHex.apply(n);
}

使い所

関数が特定のコンテキスト(クラスやオブジェクト)内で呼ばれることを期待している時など

this の型を知ることで、その関数を適切なコンテキストでのみ呼び出せるように制約を設ける高階関数を作成でき、誤ったコンテキストでの関数の使用を防ぐことができる
既存の関数型から this の型を抽出し、新たなコンテキストでの再利用や拡張ができ、既存の関数の振る舞いを保ちつつ、異なる this コンテキストでの使用を許容する新しい関数型を作成できる。

class MyClass {
  name: string;

  constructor(name: string) {
    this.name = name;
  }

  greet() {
    return `Hello, my name is ${this.name}`;
  }
}

// ThisParameterTypeを使用してgreetメソッドのthisの型を取得
type GreetThisParameter = ThisParameterType<typeof MyClass.prototype.greet>;

// MyClassのインスタンスを期待する高階関数
function invokeGreet(
  greetFn: (this: GreetThisParameter) => string,
  context: GreetThisParameter
) {
  return greetFn.call(context);
}

const myInstance = new MyClass("Alice");

[良い例]
ThisParameterTypeを使い、greet 関数が MyClass のインスタンスにバインドされた状態で呼び出されることが保証されている

console.log(invokeGreet(myInstance.greet, myInstance)); // "Hello, my name is Alice" を出力

[悪い例]
greetFunction は MyClass のインスタンス myInstance から切り離され、this.name は undefined になる。
これは greet メソッドが this を通じて name プロパティにアクセスしようとするためだが、greetFunction は適切な this コンテキストを失っているため、name は存在しないことになる。

const greetFunction = myInstance.greet;
console.log(greetFunction()); // TypeError: Cannot read property 'name' of undefined

Discussion