Skip to main content

Decorator

Overview

Decorator(デコレーター)についてまとめるセクション

デコレーターとはクラスやメソッドなどの機能を拡張するための仕組み
見た目は @decorator という形で、アノテーション的に見えるけど、本質は関数になる。
最終的にはランタイムで動作し、if文と違ってクラスの定義自体に対して拡張する(=メタプログラミング)」のが特徴

function MyDecorator(target) {
console.log("decorating:", target.name);
}

@MyDecorator
class MyClass {}

// この @MyDecorator は、「MyClass に対して MyDecorator 関数を適用する」というだけの話。
// つまり、MyDecorator(MyClass) と同じことをやってる。
tip

実行時に条件分岐するだけなら if文でいい。
クラス定義そのものに対する拡張(メタ情報付与など)はデコレーターの方が楽という考え方

関数でやる vs デコレーターでやる

ただし、デコレーターは「書き方として楽」なのと、クラスの定義と一緒にスッキリ見せられる というメリットが大きい。

  • デコレーターの正体は「ただの関数呼び出し」
  • 便利なのは見た目(構文糖)とメタデータ一括管理の面
  • 「別に関数で組み込めばよくない?」→ その通り!
  • デコレーターは見た目がスッキリ
  • 宣言的に「このクラスはこう拡張する」と明示できる
  • 大きなフレームワーク(NestJSやTypeORMなど)でも一貫してこういう記述を使うので可読性・統一感が上がる

ただ、言ってしまえば「関数を作って組み込む」っていう根本の仕組みは一緒。
だから、「複雑すぎる/好みじゃない」と感じるなら、素直に関数呼び出しでやるのもぜんぜんアリ。

@MyDecorator
class MyClass {}

// でもこれ、実際はこう書いてるのと同じ
MyClass = MyDecorator(MyClass) || MyClass;

関数で拡張するパターン

「関数作って組み込めばよくない」を例にしたコード

function enhance(ClassDef) {
// クラスに新機能を付加するなど
ClassDef.prototype.newMethod = function() { console.log("new!"); };
return ClassDef;
}

class MyClass {}
const EnhancedClass = enhance(MyClass);

デコレーターで書くパターン

デコレーターの方がスッキリ書ける。

function enhance(target) {
target.prototype.newMethod = function() { console.log("new!"); };
}

@enhance
class MyClass {}