TypeScriptのデコレーター入門|メタプログラミングの基礎

先生

TypeScriptのデコレーター、使いこなせるとマジで開発効率爆上がりするよ!🚀

TypeScriptデコレーターとは?メタプログラミングの扉を開く

TypeScriptのデコレーターは、クラス、メソッド、プロパティ、パラメーターといった宣言に対して、メタプログラミング的な機能を追加する仕組みです。これにより、コードの再利用性、可読性、保守性を向上させることができます。デコレーターは、@ 記号を使って表現され、宣言の直前に記述されます。

メタプログラミングとは、プログラム自身を操作するプログラムを作成することです。デコレーターを使うことで、クラスの定義を変更したり、メソッドの実行前後に処理を追加したり、プロパティへのアクセスを制御したりすることができます。

デコレーターの基本構文と種類

TypeScriptのデコレーターは、関数として定義されます。デコレーター関数は、ターゲットとなる宣言に関する情報を受け取り、必要に応じてその宣言を修正したり、拡張したりします。

デコレーターには、大きく分けて次の4種類があります。

1. クラスデコレーター: クラス自体に適用されます。コンストラクタ関数を置き換えたり、プロトタイプを変更したりできます。

2. メソッドデコレーター: クラスのメソッドに適用されます。メソッドの実行前後に処理を追加したり、メソッドの動作を完全に置き換えたりできます。

3. プロパティデコレーター: クラスのプロパティに適用されます。プロパティへのアクセスを制御したり、プロパティの値を変更したりできます。

4. パラメーターデコレーター: メソッドのパラメーターに適用されます。パラメーターに関する情報を収集したり、パラメーターの値を検証したりできます。

基本的なデコレーターの定義:


function SimpleDecorator(target: any) {
  console.log('Decorator called!');
}

@SimpleDecorator
class MyClass {
}

クラスデコレーターの実践

クラスデコレーターは、クラスのコンストラクタ関数を受け取ります。これを利用して、クラスのインスタンス生成をフックしたり、クラスに新しいプロパティやメソッドを追加したりできます。

例:シングルトンパターンを実装するクラスデコレーター:


function Singleton<T extends {new(...args: any[]): {}}>(constructor: T) {
    let instance: T | null = null;

    return class extends constructor {
        constructor(...args: any[]) {
            super(...args);
            if (!instance) {
                instance = this;
            }
            return instance;
        }
    };
}

@Singleton
class DatabaseConnection {
    constructor() {
        console.log('Database connection established.');
    }
}

const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();

console.log(db1 === db2); // true

メソッドデコレーターでロギング処理を追加

メソッドデコレーターは、メソッドのProperty Descriptorを受け取ります。これを利用して、メソッドの実行前後にロギング処理を追加したり、メソッドの戻り値を加工したりできます。

例:メソッドの実行時間を計測するデコレーター:


function LogPerformance(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;

    descriptor.value = function(...args: any[]) {
        const start = performance.now();
        const result = originalMethod.apply(this, args);
        const end = performance.now();
        console.log(Method ${propertyKey} took ${end - start}ms);
        return result;
    };

    return descriptor;
}

class MyService {
    @LogPerformance
    doSomething() {
        //Some long operation
        for (let i = 0; i < 100000000; i++) {
             let a = Math.random() * i
        }
        return 'Done!';
    }
}

const service = new MyService();
service.doSomething();

参考リンク

まとめ

TypeScriptのデコレーターは、強力なメタプログラミング機能を提供します。クラス、メソッド、プロパティ、パラメーターを拡張することで、コードの再利用性、可読性、保守性を向上させることができます。デコレーターを理解し、適切に活用することで、より洗練されたTypeScriptコードを書くことができるでしょう。