TypeScriptにおけるデコレーター

TypeScriptにおけるデコレーター

この記事ではTypeScriptにおけるデコレーターについて説明します。

YouTube Video

TypeScriptにおけるデコレーター

TypeScriptのデコレーターは、クラス、メソッド、アクセサ、プロパティ、またはパラメーターに対して追加の機能や動作を付与するための仕組みです。デコレーターは、コードの読みやすさや再利用性を高めるための強力なツールです。

デコレーターの基本

デコレーターは、クラスまたはクラスのメンバーに追加の機能を注入するための関数です。デコレーターは、TypeScript 1.5で導入され、ECMAScriptの標準仕様にも提案されています。

1{
2  "compilerOptions": {
3    "experimentalDecorators": true
4  }
5}
  • デコレーターを利用するには、tsconfig.jsonファイルでexperimentalDecoratorsオプションを有効にする必要があります。

デコレーターの種類

TypeScriptでは、以下の5つのデコレーターを使用することができます。

  • クラスデコレーター クラスに対して適用されるデコレーターです。
  • メソッドデコレーター クラスのメソッドに対して適用されるデコレーターです。
  • アクセサデコレーター クラスのプロパティのgetterやsetterに対して適用されるデコレーターです。
  • プロパティデコレーター クラスのプロパティに対して適用されるデコレーターです。
  • パラメータデコレーター メソッドのパラメータに対して適用されるデコレーターです。

クラスデコレーター

クラスデコレーターは、クラスに対して適用されるデコレーターです。クラスデコレーターは、クラス定義のすぐ上に記述され、クラスのコンストラクタにアクセスすることができます。主にクラスの挙動を変更したり、メタデータを追加したりするために使用されます。

 1function Logger(constructor: Function) {
 2    console.log(`Class ${constructor.name} is being constructed`);
 3}
 4
 5@Logger
 6class Person {
 7    constructor(public name: string) {}
 8}
 9
10const person = new Person('John');
11// Output: Class Person is being constructed

この例では、Loggerデコレーターがクラスに適用され、クラスが初期化される際にメッセージがコンソールに表示されます。

メソッドデコレーター

メソッドデコレーターは、クラスのメソッドに適用され、メソッドの呼び出しや挙動を変更できます。メソッドデコレーターは、3つの引数を取ります。

  1. クラスのプロトタイプ
  2. メソッド名
  3. メソッドのプロパティディスクリプター
 1function LogExecutionTime(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalMethod = descriptor.value;
 3
 4    descriptor.value = function (...args: any[]) {
 5        console.time(propertyKey);
 6        const result = originalMethod.apply(this, args);
 7        console.timeEnd(propertyKey);
 8        return result;
 9    };
10}
11
12class MathOperations {
13  @LogExecutionTime
14  add(a: number, b: number): number {
15    return a + b;
16  }
17}
18
19const math = new MathOperations();
20math.add(2, 3);
21// Output: add: 0.000ms (execution time is displayed)

この例では、LogExecutionTimeデコレーターがメソッドに適用され、メソッドの実行時間がログに表示されます。

アクセサデコレーター

アクセサデコレーターは、クラスのプロパティに対するgettersetterに適用されます。プロパティの値を変更する際の動作を追加するのに便利です。

 1function LogAccess(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
 2    const originalGet = descriptor.get;
 3    const originalSet = descriptor.set;
 4
 5    if (originalGet) {
 6        descriptor.get = function () {
 7            console.log(`Getter called for ${propertyKey}`);
 8            return originalGet.call(this);
 9        };
10    }
11
12    if (originalSet) {
13        descriptor.set = function (value: any) {
14            console.log(`Setter called for ${propertyKey} with value: ${value}`);
15            originalSet.call(this, value);
16        };
17    }
18}
19
20class Car {
21    private _speed: number = 0;
22
23    @LogAccess
24    get speed() {
25        return this._speed;
26    }
27
28    set speed(value: number) {
29        this._speed = value;
30    }
31}
32
33const car = new Car();
34car.speed = 120;               // Setter called for speed with value: 120
35console.log(car.speed);       // Getter called for speed → 120

この例では、アクセサデコレーターを用いて、gettersetterが呼び出された際にログが出力されるようにしています。

プロパティデコレーター

プロパティデコレーターは、クラスのプロパティに適用されますが、プロパティの値や振る舞いを直接変更することはできません。プロパティのメタデータを取得するために使われます。

 1function Readonly(target: any, propertyKey: string) {
 2    Object.defineProperty(target, propertyKey, {
 3        writable: false
 4    });
 5}
 6
 7class Book {
 8    @Readonly
 9    title: string = "TypeScript Guide";
10}
11
12const book = new Book();
13book.title = "New Title"; // Error: Cannot assign to read only property 'title'

この例では、Readonlyデコレーターがtitleプロパティに適用され、プロパティが読み取り専用に変更されます。

パラメータデコレーター

パラメータデコレーターは、メソッドのパラメータに適用されます。通常、メタデータを格納したり、パラメータの検証に使用されます。デコレーターは、3つの引数を受け取ります。

  1. クラスのプロトタイプ
  2. メソッド名
  3. パラメータのインデックス
 1function LogParameter(target: any, propertyKey: string, parameterIndex: number) {
 2    console.log(`Parameter at index ${parameterIndex} in method ${propertyKey} was decorated.`);
 3}
 4
 5class User {
 6    greet(@LogParameter message: string) {
 7        console.log(message);
 8    }
 9}
10
11const user = new User();
12user.greet('Hello!');
13// Output: Parameter at index 0 in method greet was decorated.

この例では、LogParameterデコレーターがgreetメソッドの最初のパラメータに適用され、メソッドが呼び出された際にそのパラメータが装飾されていることがログに表示されます。

デコレーターの実際の活用例

デコレーターは、Angularなどのフレームワークでも広く使われており、特に依存性注入やメタデータの定義に使用されます。例えば、以下のように@Componentデコレーターを使用してAngularのコンポーネントを定義します。

1@Component({
2    selector: 'app-root',
3    template: '<h1>Hello World</h1>',
4})
5export class AppComponent {}

このように、デコレーターはフレームワークやライブラリの中核的な部分として利用されることが多く、コードを簡潔で分かりやすく保つために役立ちます。

デコレーターのまとめ

TypeScriptのデコレーターは、クラスやメソッド、プロパティに対して柔軟に機能を追加できる強力なツールです。カスタムデコレーターを使えば、コードのメンテナンス性や再利用性が向上し、さらなる抽象化が可能になります。デコレーターは、AngularやNestJSなどのフレームワークでも重要な役割を果たしており、デコレーターを理解することで、これらのフレームワークの仕組みを深く理解することができます。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video