【TypeScript】デコレータの概要と使い方

TypeScript

TypeScriptのデコレータは、コードの再利用性を高めたり、特定の機能を追加する際に非常に便利なツールです。

本記事では、デコレータの基本的な概念から具体的な使い方までをわかりやすく解説します。

デコレータを使用するための環境設定

TypeScriptでは、デコレータはデフォルトで無効化されています。
そのため、tsconfig.json を編集して有効化する必要があります。

tsconfig.jsonについて

TypeScriptでは、tsconfig.jsonはプロジェクト単位で設定される重要なファイルです。
このファイルを用いることで、コンパイル設定やプロジェクト全体の振る舞いを管理できます。

初めてプロジェクトを作成する場合や、tsconfig.jsonを編集する手順については、以下の記事を参考にしてください:
➡ 【TypeScript】プロジェクト作成ガイドとtsconfig.jsonの基本

デコレータを有効化する設定

tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}
  • "experimentalDecorators": true
    • デコレータ機能を有効化する設定です。
  • "emitDecoratorMetadata": true
    • メタデータを利用する機能を有効化する設定です。

設定を保存したら、以降に示すサンプルコードを実際に動かすための準備完了です。

デコレータの基本概念

デコレータは、クラスやメソッド、プロパティに追加機能を付与する特別な構文です。

デコレータは、次の4つの対象に使用できます。

  • クラス
  • メソッド
  • メソッドの引数
  • プロパティ

デコレータは「@」(アットマーク)を使用して、次のようなフォーマットで記述します。

@デコレータ

例えば、クラスデコレータであれば、以下のようになります。

TypeScript
function Logger(target: Function) {
  console.log(`クラスが定義されました: ${target.name}`);
}

@Logger
class ExampleClass {
  // クラスの内容
}

サンプルプログラムの説明

上記のサンプルプログラムは、クラスの定義時にログを出力するシンプルなデコレータの例です。

デコレータ「@Logger」がクラス「ExampleClass」の上に付与されることで、このクラスが定義された時点で、コンソールにクラス名が表示されます。

仕組みは次の通りです。

  • Logger関数がクラスコンストラクタ(Function)を引数 target として受け取ります。
  • 関数内で target.name を使ってクラス名を取得し、ログに出力します。

デコレータの種類と使用例

この章では、主要なデコレータの種類を取り上げ、それぞれの使用例を示します。

クラスデコレータ

クラス全体に影響を与えるデコレータで、クラス全体やそのプロトタイプに新しいプロパティの追加を防ぎ、不変性を確保する目的で使用されます。

TypeScript
function Sealed(target: Function) {
  Object.seal(target);
  Object.seal(target.prototype);
}

@Sealed
class SealedClass {
  constructor(public name: string) {}
}

サンプルプログラムの説明

上記のサンプルプログラムでは、まずデコレータ「@Sealed」がクラス「SealedClass」に付与されます。
クラスが定義された際に、Object.seal が実行され、クラスそのものとそのプロトタイプに対して変更が制限されます。
なお、プロパティの追加はできませんが、既存のプロパティの値の変更は可能です。

仕組みは次の通りです。

  • デコレータ関数「Sealed」が、クラスのコンストラクタ(Function)を引数 target として受け取ります。
  • JavaScriptの Object.seal を使用して、以下の操作を行います。
    • クラス本体: Object.seal(target) で、新しい静的プロパティの追加を禁止。
    • クラスのプロトタイプ: Object.seal(target.prototype) で、インスタンスメソッドやプロパティの追加を禁止。

メソッドデコレータ

メソッドデコレータは、特定のメソッドの動作を変更します。
メソッドの実行を監視し、呼び出し時にログを記録するために使用されます。

TypeScript
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log(`${propertyKey}が呼び出されました`);
    return original.apply(this, args);
  };
}

class Sample {

  @Log
  greet() {
    console.log('Hello!');
  }
}

サンプルプログラムの説明

上記のサンプルプログラムでは、まずデコレータ「@Log」がメソッド「greet」に付与されます。
メソッドの呼び出し時に、デコレータによってコンソールに「greetが呼び出されました」というメッセージが表示されます。

仕組みは次の通りです。

  • デコレータは descriptor.value(元のメソッドの実行ロジック)を変更します。
  • 元のメソッドをラップし、追加の処理(ログ出力)を挟んだ後に元のメソッドを実行します。

プロパティデコレータ

プロパティのメタデータを付加します。
プロパティデコレータは、プロパティが宣言された際に、それを監視する目的で使用されます。

TypeScript
function PropertyDecorator(target: any, propertyKey: string) {
  console.log(`${propertyKey}がプロパティとして宣言されました`);
}

class Example {

  @PropertyDecorator
  title: string = 'タイトル';
}

サンプルプログラムの説明

上記のサンプルプログラムでは、まずデコレータ「@PropertyDecorator」がプロパティ「title」に付与されます。
プロパティが定義される時点で、コンソールにプロパティ名が表示されます。

仕組みは次の通りです。

  • デコレータ関数は対象クラスのインスタンスやプロトタイプ(target)、プロパティ名(propertyKey)を受け取ります。
  • 対象プロパティに関する情報をログとして出力します。

パラメータデコレータ

パラメータデコレータは、メソッドの引数にロジックを追加します。
主にメソッドの引数に特定の処理を施す目的で使用されます。

TypeScript
function ParamDecorator(target: Object, propKey: string, paramIndex: number) {
  console.log(`${propKey}の${paramIndex}番目のパラメータがデコレートされました`);
}

class Sample {
  greet(@ParamDecorator message: string) {
    console.log(message);
  }
}

サンプルプログラムの説明

上記のサンプルプログラムでは、まずデコレータ「@ParamDecorator」がメソッドの引数「message」に付与されます。
パラメータが宣言されたタイミングで、コンソールにその情報が表示されます。

仕組みは次の通りです。

  • デコレータ関数は対象クラスのインスタンス(target)、メソッド名(propKey)、引数のインデックス(paramIndex)を受け取ります。
  • 対象の引数についてメタ情報を記録(ログ出力)します。

デコレータの実用例

  • ログ記録:特定のメソッドが実行された際にログを残す仕組み。
  • 認証:アクセス制御をデコレータで実現。
  • データ検証:入力データのヴァリデーション。

まとめ

デコレータは、コードをより簡潔に、強力にするための便利なツールです。

本記事を通じて、デコレータの概要と基本的な使い方を理解していただければ幸いです。


本記事についての質問、誤りの指摘、ご意見ご感想などありましたら、ぜひコメントください。

それでは、最後までお読みいただき、ありがとうございます。

コメント

タイトルとURLをコピーしました