TypeScriptに導入されたデコレーターについて

2024.6.16

TypeScriptは、静的型付けの強力な機能とJavaScriptの柔軟性を兼ね備えたプログラミング言語です。そのTypeScriptにおける高度な機能の一つが「デコレーター」です。デコレーターは、クラスやメソッド、プロパティ、パラメータなどに対してメタプログラミングを行うための機能です。本記事では、デコレーターの基本概念と、その使いどころについて解説します。

デコレーターとは?

デコレーターは、関数を使ってクラスやクラスメンバーの振る舞いを修正または拡張する方法です。デコレーターは以下のように宣言されます:

typescriptコードをコピーする<code>function decorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    // デコレーターの処理
}
</code>

デコレーターを適用するには、クラスやクラスメンバーの上に @decorator と書くだけです。

デコレーターの種類

デコレーターには主に以下の4種類があります:

  1. クラスデコレーター:クラス全体に適用されるデコレーター
  2. メソッドデコレーター:メソッドに適用されるデコレーター
  3. アクセサデコレーター:アクセサ(getter/setter)に適用されるデコレーター
  4. プロパティデコレーター:プロパティに適用されるデコレーター
  5. パラメータデコレーター:メソッドのパラメータに適用されるデコレーター

デコレーターの使いどころ

以下に、デコレーターの典型的な使いどころをいくつか紹介します。

1. ログ出力

メソッドが呼び出されるたびにログを出力するデコレーターを作成することで、デバッグやトラブルシューティングが容易になります。

typescriptコードをコピーする<code>function logMethod(target: any, propertyName: string, propertyDesciptor: PropertyDescriptor): PropertyDescriptor {
    const method = propertyDesciptor.value;

    propertyDesciptor.value = function(...args: any[]) {
        console.log(`Calling ${propertyName} with arguments: ${JSON.stringify(args)}`);
        const result = method.apply(this, args);
        console.log(`Result: ${result}`);
        return result;
    };

    return propertyDesciptor;
}

class Example {
    @logMethod
    sum(a: number, b: number): number {
        return a + b;
    }
}

const example = new Example();
example.sum(2, 3);
</code>

2. アクセス制御

メソッドへのアクセスを制御するデコレーターを作成することで、セキュリティを強化できます。

typescriptコードをコピーする<code>function adminOnly(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value;

    descriptor.value = function(...args: any[]) {
        if (!this.isAdmin) {
            throw new Error("Unauthorized access");
        }
        return method.apply(this, args);
    };
}

class UserService {
    isAdmin = false;

    @adminOnly
    deleteUser(userId: string) {
        console.log(`User ${userId} deleted`);
    }
}

const service = new UserService();
try {
    service.deleteUser("123");
} catch (e) {
    console.log(e.message); // Unauthorized access
}
</code>

3. データバリデーション

メソッドの引数をバリデーションするデコレーターを作成することで、データの整合性を保つことができます。

typescriptコードをコピーする<code>function validate(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value;

    descriptor.value = function(...args: any[]) {
        if (args.some(arg => arg == null)) {
            throw new Error("Invalid arguments");
        }
        return method.apply(this, args);
    };
}

class UserService {
    @validate
    createUser(name: string, age: number) {
        console.log(`User created: ${name}, ${age}`);
    }
}

const service = new UserService();
try {
    service.createUser("John", 25); // OK
    service.createUser(null, 25); // Error: Invalid arguments
} catch (e) {
    console.log(e.message);
}
</code>

4. データキャッシング

計算結果をキャッシュするデコレーターを作成することで、パフォーマンスを向上させることができます。

typescriptコードをコピーする<code>function cache(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value;
    const cacheKey = Symbol(`${propertyName}_cache`);

    descriptor.value = function(...args: any[]) {
        if (!this[cacheKey]) {
            this[cacheKey] = method.apply(this, args);
        }
        return this[cacheKey];
    };
}

class MathService {
    @cache
    expensiveCalculation(a: number, b: number) {
        console.log("Performing expensive calculation...");
        return a + b;
    }
}

const service = new MathService();
console.log(service.expensiveCalculation(2, 3)); // Performing expensive calculation...
console.log(service.expensiveCalculation(2, 3)); // Cached result
</code>

5. デフォルト値の設定

プロパティにデフォルト値を設定するデコレーターを作成することで、初期化処理を簡略化できます。

typescriptコードをコピーする<code>function defaultValue(value: any) {
    return function(target: any, propertyName: string) {
        target[propertyName] = value;
    };
}

class Example {
    @defaultValue(10)
    value: number;
}

const example = new Example();
console.log(example.value); // 10
</code>

まとめ

デコレーターは、TypeScriptの強力な機能であり、コードの再利用性や保守性を高めることができます。デコレーターを使うことで、ロギング、アクセス制御、データバリデーション、キャッシング、デフォルト値の設定など、様々な用途に応じた柔軟なコードを書くことができます。デコレーターを理解し活用することで、より効率的で保守しやすいアプリケーションを開発する手助けとなるでしょう。

ぜひ、この機会にTypeScriptのデコレーターを試してみてください。

Related Posts