著者はCOVID-19救済基金を選択し、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

TypeScript は、 JavaScript 言語の拡張であり、コンパイル時の型チェッカーでJavaScriptのランタイムを使用します。 この組み合わせにより、開発者は完全なJavaScriptエコシステムと言語機能を使用できると同時に、オプションの静的型チェック、列挙型、クラス、およびインターフェースをその上に追加できます。 それらの追加機能の1つは、デコレータのサポートです。

デコレータは、クラスのメンバーまたはクラス自体を追加の機能で装飾する方法です。 デコレータをクラスまたはクラスメンバーに適用すると、実際には、デコレーションされているものの詳細を受け取る関数が呼び出されます。デコレータの実装は、コードを動的に変換し、機能を追加し、ボイラープレートコードの削減。 これらは、TypeScriptでメタプログラミングを行う方法です。これは、プログラマーがアプリケーション自体からの他のコードをデータとして使用するコードを作成できるようにするプログラミング手法です。

現在、ECMAScript標準にデコレータを追加するstage-2提案があります。 まだJavaScriptの機能ではないため、TypeScriptは、実験的なフラグの下で、独自のデコレータの実装を提供します。

このチュートリアルでは、TypeScriptでクラスとクラスメンバー用に独自のデコレータを作成する方法と、それらの使用方法を示します。 さまざまなコードサンプルを紹介します。これらのサンプルは、独自のTypeScript環境、またはブラウザで直接TypeScriptを記述できるオンライン環境である TypeScriptPlaygroundで実行できます。

前提条件

このチュートリアルに従うには、次のものが必要です。

  • TypeScriptプログラムを実行して、例に従うことができる環境。 これをローカルマシンに設定するには、次のものが必要になります。 TypeScript関連のパッケージを処理する開発環境を実行するためにインストールされたNodeとnpm(またはyarn)の両方。 このチュートリアルは、Node.jsバージョン14.3.0およびnpmバージョン6.14.5でテストされました。 macOSまたはUbuntu18.04にインストールするには、「Node.jsをインストールしてmacOSにローカル開発環境を作成する方法」または「Ubuntu18.04にNode.jsをインストールする方法」の「PPAを使用したインストール」セクションの手順に従います。 これは、Windows Subsystem for Linux(WSL)を使用している場合にも機能します。 さらに、TypeScriptコンパイラ(tsc)がマシンにインストールされている必要があります。 これを行うには、TypeScriptの公式Webサイトを参照してください。
  • ローカルマシン上にTypeScript環境を作成したくない場合は、公式の TypeScriptPlaygroundを使用してフォローできます。
  • JavaScript、特に destructuring、rest演算子 imports /exportsなどのES6+構文に関する十分な知識が必要です。 これらのトピックに関する詳細情報が必要な場合は、JavaScriptシリーズのコーディング方法を読むことをお勧めします。
  • このチュートリアルでは、TypeScriptをサポートし、インラインエラーを表示するテキストエディタの側面を参照します。 これはTypeScriptを使用するために必要ではありませんが、TypeScript機能をさらに活用します。 これらの利点を活用するには、 Visual Studio Code のようなテキストエディターを使用できます。このエディターは、TypeScriptをすぐにサポートします。 TypeScriptPlaygroundでこれらの利点を試すこともできます。

このチュートリアルに示されているすべての例は、TypeScriptバージョン4.2.2を使用して作成されています。

TypeScriptでのデコレータサポートの有効化

現在、デコレータはTypeScriptの実験的な機能であるため、最初に有効にする必要があります。 このセクションでは、TypeScriptの操作方法に応じて、TypeScriptでデコレータを有効にする方法を説明します。

TypeScriptコンパイラCLI

TypeScriptコンパイラCLI(tsc)を使用するときにデコレータのサポートを有効にするには、追加のフラグ--experimentalDecoratorsを渡すだけです。

tsc --experimentalDecorators

tsconfig.json

tsconfig.jsonファイルがあるプロジェクトで作業する場合、実験的なデコレータを有効にするには、experimentalDecoratorsプロパティをcompilerOptionsオブジェクトに追加する必要があります。

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

TypeScript Playgroundでは、デコレータはデフォルトで有効になっています。

デコレータ構文の使用

このセクションでは、TypeScriptクラスにデコレータを適用します。

TypeScriptでは、特別な構文@expressionを使用してデコレータを作成できます。ここで、expressionは、実行時にデコレータのターゲットに関する詳細とともに自動的に呼び出される関数です。

デコレータのターゲットは、それらを追加する場所によって異なります。 現在、デコレータはクラスの次のコンポーネントに追加できます。

  • クラス宣言自体
  • プロパティ
  • アクセサー
  • メソッド
  • パラメーター

たとえば、クラス内でObject.sealを呼び出すsealedというデコレータがあるとします。 デコレータを使用するには、次のように記述できます。

@sealed
class Person {}

強調表示されたコードで、sealedデコレータのターゲット(この場合はPersonクラス宣言)の直前にデコレータを追加したことに注意してください。

同じことが他のすべての種類のデコレータにも当てはまります。

@classDecorator
class Person {
  @propertyDecorator
  public name: string;

  @accessorDecorator
  get fullName() {
    // ...
  }

  @methodDecorator
  printName(@parameterDecorator prefix: string) {
    // ...
  }
}

複数のデコレータを追加するには、それらを次々に追加します。

@decoratorA
@decoratorB
class Person {}

TypeScriptでのクラスデコレータの作成

このセクションでは、TypeScriptでクラスデコレータを作成する手順を説明します。

@decoratorAというデコレータの場合、TypeScriptに関数decoratorAを呼び出すように指示します。 decoratorA関数は、コードでデコレータをどのように使用したかについての詳細とともに呼び出されます。 たとえば、デコレータをクラス宣言に適用した場合、関数はクラスに関する詳細を受け取ります。 この関数は、デコレータが機能するためのスコープ内にある必要があります。

独自のデコレータを作成するには、デコレータと同じ名前の関数を作成する必要があります。 つまり、前のセクションで見たsealedクラスデコレータを作成するには、特定のパラメータセットを受け取るsealed関数を作成する必要があります。 まさにそれをしましょう:

@sealed
class Person {}

function sealed(target: Function) {
  Object.seal(target);
  Object.seal(target.prototype);
}

デコレータに渡されるパラメータは、デコレータが使用される場所によって異なります。 最初のパラメータは一般にtargetと呼ばれます。

sealedデコレータはクラス宣言でのみ使用されるため、関数はtargetという単一のパラメータを受け取ります。これはFunctionタイプになります。 これは、デコレータが適用されたクラスのコンストラクタになります。

次に、sealed関数で、クラスコンストラクターであるtargetと、それらのプロトタイプでObject.sealを呼び出します。 これを行うと、クラスコンストラクターまたはそのプロパティに新しいプロパティを追加できなくなり、既存のプロパティは構成不可としてマークされます。

デコレータを使用する場合、現在、targetのTypeScriptタイプを拡張することはできないことを覚えておくことが重要です。 これは、たとえば、デコレータを使用してクラスに新しいフィールドを追加し、それをタイプセーフにすることができないことを意味します。

sealedクラスデコレータに値を返した場合、この値がクラスの新しいコンストラクタ関数になります。 これは、クラスコンストラクターを完全に上書きする場合に役立ちます。

最初のデコレータを作成し、それをクラスで使用しました。 次のセクションでは、デコレータファクトリを作成する方法を学習します。

デコレータファクトリの作成

適用するときにデコレータに追加のオプションを渡す必要がある場合があります。そのためには、デコレータファクトリを使用する必要があります。 このセクションでは、これらのファクトリを作成して使用する方法を学習します。

デコレータファクトリは、別の関数を返す関数です。 デコレータの実装自体ではないため、この名前が付けられています。 代わりに、デコレータの実装を担当する別の関数を返し、ラッパー関数として機能します。 これらは、クライアントコードがデコレータを使用するときにオプションを渡すことができるようにすることで、デコレータをカスタマイズ可能にするのに役立ちます。

decoratorAというクラスデコレータがあり、ブールフラグのように、デコレータを呼び出すときに設定できるオプションを追加したいとします。 これは、次のようなデコレータファクトリを作成することで実現できます。

const decoratorA = (someBooleanFlag: boolean) => {
  return (target: Function) => {
  }
}

ここで、decoratorA関数は、デコレータの実装を含む別の関数を返します。 デコレータファクトリが唯一のパラメータとしてブールフラグを受け取る方法に注意してください。

const decoratorA = (someBooleanFlag: boolean) => {
  return (target: Function) => {
  }
}

デコレータを使用するときに、このパラメータの値を渡すことができます。 次の例で強調表示されているコードを参照してください。

const decoratorA = (someBooleanFlag: boolean) => {
  return (target: Function) => {
  }
}

@decoratorA(true)
class Person {}

ここで、decoratorAデコレータを使用すると、someBooleanFlagパラメータがtrueに設定された状態でデコレータファクトリが呼び出されます。 次に、デコレータの実装自体が実行されます。 これにより、デコレータの使用方法に基づいてデコレータの動作を変更できるため、デコレータを簡単にカスタマイズして、アプリケーション全体で再利用できます。

デコレータファクトリが期待するすべてのパラメータを渡す必要があることに注意してください。 次の例のように、パラメータを渡さずにデコレータを適用した場合:

const decoratorA = (someBooleanFlag: boolean) => {
  return (target: Function) => {
  }
}

@decoratorA
class Person {}

TypeScriptコンパイラは2つのエラーを出しますが、これはデコレータのタイプによって異なる場合があります。 クラスデコレータの場合、エラーは12381240です。

Output
Unable to resolve signature of class decorator when called as an expression. Type '(target: Function) => void' is not assignable to type 'typeof Person'. Type '(target: Function) => void' provides no match for the signature 'new (): Person'. (1238) Argument of type 'typeof Person' is not assignable to parameter of type 'boolean'. (2345)

パラメータを受け取り、これらのパラメータに基づいて動作を変更できるデコレータファクトリを作成しました。 次のステップでは、プロパティデコレータを作成する方法を学習します。

プロパティデコレータの作成

クラスプロパティは、デコレータを使用できるもう1つの場所です。 このセクションでは、それらを作成する方法を見ていきます。

プロパティデコレータは、次のパラメータを受け取ります。

  • 静的プロパティの場合、クラスのコンストラクター関数。 他のすべてのプロパティについては、クラスのプロトタイプ。
  • メンバーの名前。

現在、プロパティ記述子をパラメータとして取得する方法はありません。 これは、プロパティデコレータがTypeScriptで初期化される方法によるものです。

メンバーの名前をコンソールに出力するデコレータ関数は次のとおりです。

const printMemberName = (target: any, memberName: string) => {
  console.log(memberName);
};

class Person {
  @printMemberName
  name: string = "Jon";
}

上記のTypeScriptコードを実行すると、コンソールに次のように出力されます。

Output
name

プロパティデコレータを使用して、装飾されているプロパティを上書きできます。 これは、 Object.defineProperty を、プロパティの新しいセッターおよびゲッターと一緒に使用することで実行できます。 allowlistという名前のデコレータを作成する方法を見てみましょう。これにより、プロパティを静的許可リストに存在する値にのみ設定できます。

const allowlist = ["Jon", "Jane"];

const allowlistOnly = (target: any, memberName: string) => {
  let currentValue: any = target[memberName];

  Object.defineProperty(target, memberName, {
    set: (newValue: any) => {
      if (!allowlist.includes(newValue)) {
        return;
      }
      currentValue = newValue;
    },
    get: () => currentValue
  });
};

まず、コードの先頭に静的な許可リストを作成します。

const allowlist = ["Jon", "Jane"];

次に、プロパティデコレータの実装を作成します。

const allowlistOnly = (target: any, memberName: string) => {
  let currentValue: any = target[memberName];

  Object.defineProperty(target, memberName, {
    set: (newValue: any) => {
      if (!allowlist.includes(newValue)) {
        return;
      }
      currentValue = newValue;
    },
    get: () => currentValue
  });
};

targetのタイプとしてanyをどのように使用しているかに注意してください。

const allowlistOnly = (target: any, memberName: string) => {

プロパティデコレータの場合、ターゲットパラメータのタイプは、クラスのコンストラクタまたはクラスのプロトタイプのいずれかになります。この状況では、anyを使用する方が簡単です。

デコレータ実装の最初の行には、デコレーションされているプロパティの現在の値をcurrentValue変数に格納しています。

  let currentValue: any = target[memberName];

静的プロパティの場合、これはデフォルト値(存在する場合)に設定されます。 非静的プロパティの場合、これは常にundefinedになります。 これは、実行時に、コンパイルされたJavaScriptコードで、インスタンスプロパティがデフォルト値に設定される前にデコレータが実行されるためです。

次に、Object.definePropertyを使用してプロパティをオーバーライドします。

  Object.defineProperty(target, memberName, {
    set: (newValue: any) => {
      if (!allowlist.includes(newValue)) {
        return;
      }
      currentValue = newValue;
    },
    get: () => currentValue
  });

Object.defineProperty呼び出しには、gettersetterがあります。 getterは、currentValue変数に格納されている値を返します。 setterは、currentVariableの値が許可リスト内にある場合はnewValueに設定します。

今書いたデコレータを使ってみましょう。 次のPersonクラスを作成します。

class Person {
  @allowlistOnly
  name: string = "Jon";
}

次に、クラスの新しいインスタンスを作成し、設定をテストしてnameインスタンスプロパティを取得します。

const allowlist = ["Jon", "Jane"];

const allowlistOnly = (target: any, memberName: string) => {
  let currentValue: any = target[memberName];

  Object.defineProperty(target, memberName, {
    set: (newValue: any) => {
      if (!allowlist.includes(newValue)) {
        return;
      }
      currentValue = newValue;
    },
    get: () => currentValue
  });
};

class Person {
  @allowlistOnly
  name: string = "Jon";
}

const person = new Person();
console.log(person.name);

person.name = "Peter";
console.log(person.name);

person.name = "Jane";
console.log(person.name);

コードを実行すると、次の出力が表示されます。

Output
Jon Jon Jane

Peterは許可リストにないため、値がPeterに設定されることはありません。

コードをもう少し再利用可能にして、デコレータを適用するときに許可リストを設定できるようにするにはどうすればよいでしょうか。 これは、デコレータファクトリの優れたユースケースです。 allowlistOnlyデコレータをデコレータファクトリに変えて、まさにそれを実行しましょう。

const allowlistOnly = (allowlist: string[]) => {
  return (target: any, memberName: string) => {
    let currentValue: any = target[memberName];

    Object.defineProperty(target, memberName, {
      set: (newValue: any) => {
        if (!allowlist.includes(newValue)) {
          return;
        }
        currentValue = newValue;
      },
      get: () => currentValue
    });
  };
}

ここでは、以前の実装を別の関数であるデコレータファクトリにラップしました。 デコレータファクトリは、文字列の配列であるallowlistと呼ばれる単一のパラメータを受け取ります。

デコレータを使用するには、次の強調表示されたコードのように、許可リストを渡す必要があります。

class Person {
  @allowlistOnly(["Claire", "Oliver"])
  name: string = "Claire";
}

前に書いたものと同様のコードを実行してみてください。ただし、新しい変更が加えられています。

const allowlistOnly = (allowlist: string[]) => {
  return (target: any, memberName: string) => {
    let currentValue: any = target[memberName];

    Object.defineProperty(target, memberName, {
      set: (newValue: any) => {
        if (!allowlist.includes(newValue)) {
          return;
        }
        currentValue = newValue;
      },
      get: () => currentValue
    });
  };
}

class Person {
  @allowlistOnly(["Claire", "Oliver"])
  name: string = "Claire";
}

const person = new Person();
console.log(person.name);
person.name = "Peter";
console.log(person.name);
person.name = "Oliver";
console.log(person.name);

コードは次の出力を提供するはずです。

Output
Claire Claire Oliver

Peterが指定された許可リストにないため、person.namePeterに設定されることはありません。

通常のデコレータ関数とデコレータファクトリの両方を使用して最初のプロパティデコレータを作成したので、クラスアクセサのデコレータを作成する方法を見てみましょう。

アクセサデコレータの作成

このセクションでは、クラスアクセサーを装飾する方法を見ていきます。

プロパティデコレータと同様に、アクセサで使用されるデコレータは次のパラメータを受け取ります。

  1. 静的プロパティの場合、クラスのコンストラクター関数、他のすべてのプロパティの場合、クラスのプロトタイプ。
  2. メンバーの名前。

ただし、プロパティデコレータとは異なり、アクセサメンバーのプロパティ記述子を使用した3番目のパラメータも受け取ります。

プロパティ記述子には特定のメンバーのセッターとゲッターの両方が含まれているため、アクセサーデコレーターは単一メンバーのセッターまたはゲッターの両方にのみ適用でき、両方には適用できません。

アクセサデコレータから値を返す場合、この値は、ゲッタメンバーとセッタメンバーの両方のアクセサの新しいプロパティ記述子になります。

ゲッター/セッターアクセサーのenumerableフラグを変更するために使用できるデコレーターの例を次に示します。

const enumerable = (value: boolean) => {
  return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
    propertyDescriptor.enumerable = value;
  }
}

この例では、デコレータファクトリをどのように使用しているかに注意してください。 これにより、デコレータを呼び出すときに列挙可能なフラグを指定できます。 デコレータの使用方法は次のとおりです。

class Person {
  firstName: string = "Jon"
  lastName: string = "Doe"

  @enumerable(true)
  get fullName () {
    return `${this.firstName} ${this.lastName}`;
  }
}

アクセサデコレータは、プロパティデコレータに似ています。 唯一の違いは、プロパティ記述子を持つ3番目のパラメーターを受け取ることです。 最初のアクセサデコレータを作成したので、次のセクションでは、メソッドデコレータを作成する方法を示します。

メソッドデコレータの作成

このセクションでは、メソッドデコレータの使用方法を見ていきます。

メソッドデコレータの実装は、アクセサデコレータを作成する方法と非常によく似ています。 デコレータの実装に渡されるパラメータは、アクセサデコレータに渡されるパラメータと同じです。

以前に作成したものと同じenumerableデコレータを再利用しましょう。ただし、今回は次のPersonクラスのgetFullNameメソッドで使用します。

const enumerable = (value: boolean) => {
  return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
    propertyDescriptor.enumerable = value;
  }
}

class Person {
  firstName: string = "Jon"
  lastName: string = "Doe"

  @enumerable(true)
  getFullName () {
    return `${this.firstName} ${this.lastName}`;
  }
}

メソッドデコレータから値を返した場合、この値がメソッドの新しいプロパティ記述子になります。

メソッドが使用されたときに渡されたメッセージをコンソールに出力し、メソッドが非推奨であることを示すメッセージをログに記録するdeprecatedデコレータを作成しましょう。

const deprecated = (deprecationReason: string) => {
  return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
    return {
      get() {
        const wrapperFn = (...args: any[]) => {
          console.warn(`Method ${memberName} is deprecated with reason: ${deprecationReason}`);
          propertyDescriptor.value.apply(this, args)
        }

        Object.defineProperty(this, memberName, {
            value: wrapperFn,
            configurable: true,
            writable: true
        });
        return wrapperFn;
      }
    }
  }
}

ここでは、デコレータファクトリを使用してデコレータを作成しています。 このデコレータファクトリは、タイプstringの単一の引数を受け取ります。これが、以下の強調表示された部分に示されているように、非推奨の理由です。

const deprecated = (deprecationReason: string) => {
  return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
    // ...
  }
}

deprecationReasonは、後で非推奨メッセージをコンソールに記録するときに使用されます。 deprecatedデコレータの実装では、値を返します。 メソッドデコレータから値を返す場合、この値はこのメンバーのプロパティ記述子を上書きします。

これを利用して、装飾されたクラスメソッドにgetterを追加します。 このようにして、メソッド自体の実装を変更できます。

しかし、メソッドの新しいプロパティデコレータを返す代わりに、Object.definePropertyを使用しないのはなぜですか? これは、thisの値にアクセスする必要があるために必要です。この値は、非静的クラスメソッドの場合、クラスインスタンスにバインドされます。 Object.definePropertyを直接使用した場合、thisの値を取得する方法はありません。また、メソッドがthisを使用した場合、デコレータはコードを破壊します。デコレータ実装内からラップされたメソッドを実行する場合。

あなたの場合、getter自体には、非静的メソッドの場合はクラスインスタンスにバインドされ、静的メソッドの場合はクラスコンストラクターにバインドされたthis値があります。

次に、getter内で、wrapperFnと呼ばれるラッパー関数をローカルで作成します。この関数は、console.warnを使用してコンソールにメッセージを記録し、受信したdeprecationReasonを渡します。デコレータファクトリから、propertyDescriptor.value.apply(this, args)を使用して元のメソッドを呼び出します。これにより、元のメソッドが呼び出され、this値がクラスインスタンスに正しくバインドされます。静的メソッド。

次に、definePropertyを使用して、クラス内のメソッドの値を上書きします。 これはメモ化メカニズムのように機能します。同じメソッドを複数回呼び出すと、getterは呼び出されず、wrapperFnが直接呼び出されるためです。 これで、Object.definePropertyを使用して、wrapperFnを値として持つようにクラスのメンバーを設定しています。

deprecatedデコレータを使用してみましょう。

const deprecated = (deprecationReason: string) => {
  return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
    return {
      get() {
        const wrapperFn = (...args: any[]) => {
          console.warn(`Method ${memberName} is deprecated with reason: ${deprecationReason}`);
          propertyDescriptor.value.apply(this, args)
        }

        Object.defineProperty(this, memberName, {
            value: wrapperFn,
            configurable: true,
            writable: true
        });
        return wrapperFn;
      }
    }
  }
}

class TestClass {
  static staticMember = true;

  instanceMember: string = "hello"

  @deprecated("Use another static method")
  static deprecatedMethodStatic() {
    console.log('inside deprecated static method - staticMember =', this.staticMember);
  }

  @deprecated("Use another instance method")
  deprecatedMethod () {
    console.log('inside deprecated instance method - instanceMember =', this.instanceMember);
  }
}

TestClass.deprecatedMethodStatic();

const instance = new TestClass();
instance.deprecatedMethod();

ここでは、静的と非静的の2つのプロパティを持つTestClassを作成しました。 また、静的メソッドと非静的メソッドの2つのメソッドを作成しました。

次に、deprecatedデコレータを両方のメソッドに適用します。 コードを実行すると、コンソールに次のように表示されます。

Output
(warning) Method deprecatedMethodStatic is deprecated with reason: Use another static method inside deprecated static method - staticMember = true (warning)) Method deprecatedMethod is deprecated with reason: Use another instance method inside deprecated instance method - instanceMember = hello

これは、両方のメソッドがラッパー関数で正しくラップされたことを示しています。ラッパー関数は、非推奨の理由とともにメッセージをコンソールに記録します。

これで、TypeScriptを使用して最初のメソッドデコレータが作成されました。 次のセクションでは、パラメータデコレータであるTypeScriptでサポートされている最後のデコレータタイプを作成する方法を示します。

パラメータデコレータの作成

パラメータデコレータは、クラスメソッドのパラメータで使用できます。 このセクションでは、作成方法を学習します。

パラメータで使用されるデコレータ関数は、次のパラメータを受け取ります。

  1. 静的プロパティの場合、クラスのコンストラクター関数。 他のすべてのプロパティについては、クラスのプロトタイプ。
  2. メンバーの名前。
  3. メソッドのパラメーターリスト内のパラメーターのインデックス。

パラメータ自体に関連するものを変更することはできないため、このようなデコレータは、パラメータの使用法自体を監視する場合にのみ役立ちます( reflect-metadata などのより高度なものを使用する場合を除く)。

これは、デコレーションされたパラメーターのインデックスをメソッド名とともに出力するデコレーターの例です。

function print(target: Object, propertyKey: string, parameterIndex: number) {
  console.log(`Decorating param ${parameterIndex} from ${propertyKey}`);
}

次に、次のようにパラメータデコレータを使用できます。

class TestClass {
  testMethod(param0: any, @print param1: any) {}
}

上記のコードを実行すると、コンソールに次のように表示されます。

Output
Decorating param 1 from testMethod

これで、パラメーターデコレーターを作成して実行し、装飾されたパラメーターのインデックスを返す結果を出力しました。

結論

このチュートリアルでは、TypeScriptでサポートされているすべてのデコレータを実装し、それらをクラスで使用して、それぞれの違いを学習しました。 これで、独自のデコレータを作成してコードベースの定型コードを減らしたり、Mobxなどのライブラリでデコレータをより自信を持って使用したりできます。

TypeScriptのその他のチュートリアルについては、TypeScriptシリーズのコーディング方法ページをご覧ください。