@decorator デコレータ
最終更新:2026-10-22
@decorator デコレータ
デコレータはクラス、メソッド、プロパティ、パラメータの前に付ける特殊な構文 @name です。1枚の関数で包んでクラスに振る舞い(ログ、検証、依存性の注入)を加え、クラス本体のコードを変えずに済みます。TS においてデコレータはまだ実験的な機能で、tsconfig で experimentalDecorators を有効にする必要があります。NestJS、TypeORM などのフレームワークが大量に使っており、これらのフレームワークのソースコードを読むための必修項目です。
| グループ | 設定と実践 |
|---|---|
| 種類 | 構文 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
// クラスデコレーター:コンストラクターを受け取る
function sealed(Ctor: Function): void {
Object.seal(Ctor);
Object.seal(Ctor.prototype);
}
// メソッドデコレーター:(プロトタイプ, メソッド名, プロパティ記述子) を受け取る
function logged(target: object, key: string, desc: PropertyDescriptor): void {
const original = desc.value;
desc.value = function (...args: unknown[]) {
console.log("call", key, args);
return original.apply(this, args);
};
}
@sealed
class Calculator {
@logged
add(a: number, b: number) { return a + b; }
}
⚙️ パラメータ
| ClassDecorator | パラメータはクラスのコンストラクタです。クラスを改変したり、新しいクラスを返して差し替えたりできます。@sealed のような「クラス全体の制約」によく使われます |
|---|---|
| MethodDecorator | クラス定義の時点で1回実行され、desc.value を書き換えて元のメソッドをラップします。新しい記述子を返せば全体を差し替えられます |
| experimentalDecorators | tsconfig のスイッチです。付けないと「デコレータは実験的機能」というエラーになります。フレームワークのエコシステム(NestJS など)は現状このバージョンに基づいています |
戻り値:クラスデコレータは新しいコンストラクタを返して元のクラスを差し替えられます(返さなければ元のクラスをそのまま使います)。メソッドデコレータは新しいプロパティ記述子を返すか、undefined を返して副作用だけで変更します。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
-> add(2, 3)
add = 5
-> mul(4, 5)
mul = 20
(トランスパイル後の実行出力。メソッドデコレータはクラス定義の時点でラップを終えています。呼び出し時にはまず -> add(2, 3) と表示してから結果を返します)
💡 ポイント
ℹ️ 説明 実行のタイミングは「メソッドの呼び出し時」ではなく「クラス定義時」です。デコレータ関数は class 宣言が評価されるときに1回だけ実行され、desc.value をラップ版に置き換えます。その後のすべての呼び出しはラップ版を通ります。
💡 ヒント デコレータにパラメータを渡したいときは「デコレータファクトリ」を使います。@log("debug") はデコレータ関数を返す関数で、外側が設定を受け取り、内側が (target, key, desc) を受け取ります。NestJS の @Injectable() に括弧が付いているのはまさにこのファクトリです。
⚠️ 注意 実験版と標準版ではシグネチャに互換性がありません。TS 5 からは experimentalDecorators を使わずに ES 標準のデコレータが使えますが、メソッドデコレータの第2パラメータは (target, key, desc) から context オブジェクトに変わります。古いプロジェクトやフレームワークのコードを読む前に、どちらの版か確認しましょう。
🏷️ 関連設定と実践
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q デコレータと普通の高階関数の違いは何ですか?
A 本質はどちらも「関数で関数を包む」ことです。違いは宣言の位置にあります。デコレータは被装飾者の上に書かれ、コンパイラが定義箇所へ接続するため、クラス/メソッドの本体は綺麗なままです。高階関数は作成箇所で明示的に包む必要があります(const add = logged(Calculator.prototype.add) のように)。デコレータは「ラベルを貼る」ようなもので、横断的関心事に向いています。
Q NestJS の @Injectable() はどう動いていますか?
A @Injectable() はデコレータファクトリで、返されたクラスデコレータがクラスにメタデータを付けます(依存性注入のコンテナがインスタンス化できる印です)。コンテナは Controller を生成するときにコンストラクタのパラメータの型/デコレータのメタデータを読み、依存を自動的に解決して注入します。デコレータ自体は注入を行わず、情報を登録するだけです。
Q 新しいプロジェクトでは実験版と標準版のどちらのデコレータを使うべきですか?
A フレームワーク次第です。NestJS/TypeORM などのエコシステムに従うなら experimentalDecorators を有効にします(現状は旧い意味論に依存しています)。純粋に自分のコードなら標準版(TS 5+ の既定)がおすすめです。ES 標準に入り「実験」の重荷がなくなりましたが、2つの版の書き方は混在できません。