TypeScriptに導入されたデコレーターについて
TypeScriptは、静的型付けの強力な機能とJavaScriptの柔軟性を兼ね備えたプログラミング言語です。そのTypeScriptにおける高度な機能の一つが「デコレーター」です。デコレーターは、クラスやメソッド、プロパティ、パラメータなどに対してメタプログラミングを行うための機能です。本記事では、デコレーターの基本概念と、その使いどころについて解説します。
デコレーターとは?
デコレーターは、関数を使ってクラスやクラスメンバーの振る舞いを修正または拡張する方法です。デコレーターは以下のように宣言されます:
typescriptコードをコピーする<code>function decorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
// デコレーターの処理
}
</code>
デコレーターを適用するには、クラスやクラスメンバーの上に @decorator
と書くだけです。
デコレーターの種類
デコレーターには主に以下の4種類があります:
- クラスデコレーター:クラス全体に適用されるデコレーター
- メソッドデコレーター:メソッドに適用されるデコレーター
- アクセサデコレーター:アクセサ(getter/setter)に適用されるデコレーター
- プロパティデコレーター:プロパティに適用されるデコレーター
- パラメータデコレーター:メソッドのパラメータに適用されるデコレーター
デコレーターの使いどころ
以下に、デコレーターの典型的な使いどころをいくつか紹介します。
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のデコレーターを試してみてください。