デコレータは、クラス、プロパティ、メソッド、またはパラメータの動作を変更する特別なアノテーションであり、追加のメタ情報または実装の置き換えを通じて行います。
通常、依存性の注入、ロギング、バリデーション、キャッシング、またはAngularのようなフレームワーク用のメタデータの宣言に使用されます。
メソッドのシンプルなデコレータの例:
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Call: ${propertyKey}(${JSON.stringify(args)})`); return original.apply(this, args); }; } class Example { @Log doSomething(a: number, b: number) { return a + b; } }
落とし穴:
experimentalDecoratorsを有効にしなければ機能しません。質問: "デコレータに適用されるメソッドの型を保証するようにパラメータを型付けすることはできますか?"
回答: ほとんどの場合、デコレータの適用時に型付けは不可能です。メタプログラミングの動的な性質のためです。ただし、ジェネリクスや追加のランタイムチェックを通じてバリデーションを追加できますが、TypeScriptのコンパイラは構造の宣言段階で保証を与えません。
例:
function MyDecorator(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<number>) { /* ... */ } // コンパイラはメソッドがnumberを返すことを保証しません
物語
デコレータが多数あるサービスのプロジェクトで、適用順序を忘れたため、プロパティデコレータがすべてのパラメータの前に適用され、Injectメタデータを失い、実行時に依存関係を解決できなくなりました。
物語
開発者がクラスのメソッドではなく通常の関数にデコレータを適用しようとし、コンパイルエラーや実行時効果の欠如に驚きました。TypeScriptの仕様では、デコレータはクラスとそのメンバーにのみ適用されます。
物語
TypeScriptのバージョンを更新し、実験的設定を行った後、カスタムDIコンテナのデコレータ機構が壊れました。新しいバージョンはReflect-metadataの明示的なサポートを要求し、それがないとすべてのメタ情報が失われることがわかりました。