【TypeScript】デコレータとECMAScript - 最新機能解説
2024-10-26
2024-10-26
概要
デコレータは、TypeScript
やJavaScriptのコードに特定のアノテーションを付与し、実行時の動作を変更するメタプログラミングの技術です。TypeScript
はJavaScriptに先駆けてデコレータの構文をサポートしており、ECMAScript標準でもデコレータの仕様がStage 3(最終段階に近い提案段階)に進んでいます。本記事では、TypeScript
とECMAScriptのデコレータ機能について、最新の動向や実装方法を解説します。
デコレータとは?
デコレータは、クラス、メソッド、プロパティ、アクセサ、メソッドパラメータなどに付与され、追加のロジックを注入する機能です。デコレータは、アプリケーションの柔軟性を高めるためにロギング、バリデーション、キャッシングなどのクロスカッティングな処理を簡潔に記述するための手段として役立ちます。
デコレータの利用例
デコレータの活用例として、ロギング機能をメソッドに追加するデコレータを見てみましょう。
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Method ${propertyKey} was called with args: ${JSON.stringify(args)}`);
return originalMethod.apply(this, args);
};
}
class Example {
@Log
greet(name: string) {
return `Hello, ${name}`;
}
}
const example = new Example();
example.greet("`TypeScript`"); // ログ出力: Method greet was called with args: ["`TypeScript`"]
この例では、Log
デコレータがgreet
メソッドの実行前にログを出力するようにしています。@Log
でメソッドにアノテーションを追加するだけで、ロギング機能を簡単に組み込むことができます。
TypeScriptでのデコレータの利用方法
TypeScriptでデコレータを有効にする
TypeScript
でデコレータを使うには、experimentalDecoratorsオプションを有効にする必要があります。tsconfig.json
に以下の設定を追加します。
{
"compilerOptions": {
"experimentalDecorators": true
}
}
デコレータの種類
TypeScript
のデコレータには以下の種類があります。
-
クラスデコレータ
クラス全体に適用し、クラスのメタデータを操作する。 -
メソッドデコレータ
特定のメソッドに適用し、メソッドの動作を変更する。 -
プロパティデコレータ
プロパティに追加し、プロパティに関するメタ情報を付与する。 -
アクセサデコレータ
get
やset
メソッドに適用して、アクセサの動作を制御する。 -
パラメータデコレータ
メソッドのパラメータにアノテーションを追加し、パラメータの情報に基づいて処理を行う。
メソッドデコレータの実装例
メソッドデコレータを用いると、メソッドの動作をラップして変更できます。以下に、指定メソッドが実行された回数をカウントするデコレータを実装します。
function CountCalls(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let callCount = 0;
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
callCount++;
console.log(`${propertyKey} has been called ${callCount} times`);
return originalMethod.apply(this, args);
};
}
class Sample {
@CountCalls
sayHello() {
console.log("Hello!");
}
}
const sample = new Sample();
sample.sayHello(); // 出力: sayHello has been called 1 times
sample.sayHello(); // 出力: sayHello has been called 2 times
この例では、sayHello
メソッドが呼ばれるたびにカウントが増加し、ログに出力されます。デコレータを使うことで、メソッドの挙動を簡単に拡張できます。
ECMAScript標準とデコレータの最新動向
ECMAScriptのデコレータ提案
ECMAScriptのデコレータ提案は、現在Stage 3にあり、JavaScriptの標準機能として導入されることが予定されています。ECMAScript標準のデコレータでは、TypeScript
のデコレータ構文と異なる部分もありますが、将来的にTypeScript
もECMAScript標準に対応する予定です。
ECMAScript標準のデコレータ構文
新しいECMAScriptデコレータは、TypeScript
と異なり、デコレータが関数であると同時に関数の結果としてプロパティを返します。以下は、新しいECMAScript標準に基づくメソッドデコレータの例です。
function LogMethod() {
return function (target, context) {
return function (...args) {
console.log(`Called ${context.name} with args: ${args}`);
return context.fn(...args);
};
};
}
class Example {
@LogMethod()
greet(name) {
return `Hello, ${name}`;
}
}
const example = new Example();
example.greet("JavaScript"); // ログ出力: Called greet with args: ["JavaScript"]
context
オブジェクトにより、メソッド名や実際の関数実装にアクセスできる点が新しい特徴です。メソッドの処理を変更するだけでなく、メタデータや実装へのアクセスが可能で、柔軟性が向上しています。
TypeScriptとECMAScriptデコレータの共存
TypeScript
のデコレータは将来的にECMAScriptの標準に沿う形で改良される見込みです。TypeScript
の現在の構文が将来的な互換性を考慮して設計されているため、TypeScript
でデコレータを使うプロジェクトも、今後の標準にスムーズに移行できるでしょう。
デコレータの活用例と応用
デコレータは、さまざまな場面で効果的に使用できます。以下に代表的なユースケースを紹介します。
ロギング機能の追加
デコレータは、メソッドやクラスの実行状況を記録するロギング機能に活用できます。開発時やデバッグ時に役立つため、クラスやメソッドに @Log
デコレータを付与することで、呼び出し状況を追跡することができます。
認証・認可の追加
デコレータを使えば、特定のメソッドにアクセス制限を設けることが可能です。例えば、管理者ユーザーのみが実行可能なメソッドにデコレータを追加し、認可処理を行うことで、セキュリティを高められます。
function AdminOnly(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
if (!this.isAdmin) {
throw new Error("Unauthorized");
}
return originalMethod.apply(this, args);
};
}
class UserActions {
isAdmin = false;
@AdminOnly
deleteUser() {
console.log("User deleted");
}
}
キャッシング
重い計算処理やデータ取得の結果をキャッシュするデコレータを実装すると、効率的なリソース利用が可能です。計算済みの結果を保存し、同じ処理を再利用することでパフォーマンスが向上します。
まとめ
デコレータは、TypeScript
およびJavaScriptにおいて、コードの再利用性や拡張性を高めるための強力なツールです。ECMAScript標準も取り入れ始めたことで、将来的にデコレータはより広く使われる機能となるでしょう。TypeScript
でのデコレータの活用は、現在のメタプログラミングや効率的なコーディングに欠かせない存在です。クラスやメソッドの処理を簡単にカスタマイズし、柔軟で拡張性の高いアプリケーション開発に役立てていきましょう。