1. ホーム
  2. タイプスクリプト

[解決済み】typescriptのデコレーターを実装するには?

2022-04-06 01:12:14

質問

TypeScript 1.5 は、現在 デコレータ .

誰か、デコレータを実装する適切な方法を示す簡単な例と、 有効なデコレータシグネチャの引数の意味を教えていただけませんか?

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
declare type PropertyDecorator = (target: Object, propertyKey: string | symbol) => void;
declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;
declare type ParameterDecorator = (target: Function, propertyKey: string | symbol, parameterIndex: number) => void;

さらに、デコレータを実装する際に留意すべきベストプラクティスがあれば教えてください。

どのように解決するのですか?

私は結局デコレーターで遊んでいて、何かの文書が出る前にこれを利用したい人のために、私が理解したことを文書化することにしました。もし何か間違いがあれば、遠慮なく編集してください。

一般的なポイント

  • デコレーターはクラスが宣言されたときに呼び出され、オブジェクトがインスタンス化されたときには呼び出されません。
  • 同じクラス/プロパティ/メソッド/パラメータに複数のデコレータを定義することができます。
  • デコレーターは、コンストラクターには使用できません。

有効なデコレータは以下の通りです。

  1. いずれかの Decorator タイプに割り当て可能 ( ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator ).
  2. 装飾された値に代入可能な値 (クラス・デコレータ、メソッド・デコレータの場合) を返します。

参照


メソッド / フォーマルアクセサデコレータ

実装パラメータです。

  • target : クラスのプロトタイプ( Object ).
  • propertyKey : メソッドの名前 ( string | symbol ).
  • descriptor : A TypedPropertyDescriptor - もし、記述子のキーについてよく知らないのであれば、以下の記事を読むことをお勧めします。 このドキュメント について Object.defineProperty (3番目のパラメータです)。

例 - 引数なし

使用します。

class MyClass {
    @log
    myMethod(arg: string) { 
        return "Message -- " + arg;
    }
}

インプリメンテーションです。

function log(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
    const originalMethod = descriptor.value; // save a reference to the original method

    // NOTE: Do not use arrow syntax here. Use a function expression in 
    // order to use the correct value of `this` in this method (see notes below)
    descriptor.value = function(...args: any[]) {
        // pre
        console.log("The method args are: " + JSON.stringify(args));
        // run and store result
        const result = originalMethod.apply(this, args);
        // post
        console.log("The return value is: " + result);
        // return the result of the original method (or modify it before returning)
        return result;
    };

    return descriptor;
}

入力です。

new MyClass().myMethod("testing");

出力します。

メソッドの引数は ["testing"] です。

戻り値は メッセージ -- テスト

注意事項

  • 記述子の値を設定する際に、矢印の構文を使用しないでください。 のコンテキストは this はインスタンスのものではありません。
  • 新しい記述子を返すことで現在の記述子を上書きするよりも、元の記述子を修正する方がよいでしょう。これにより、記述子を編集する複数のデコレータを使用しても、 他のデコレータが行ったことを上書きすることがなくなります。こうすることで、次のような使い方ができるようになります。 @enumerable(false)@log を同時に使用することができます(例. 悪い 良い )
  • 便利な : のtype引数は、typeを指定するためのものです。 TypedPropertyDescriptor は、どのようなメソッドシグネチャを使用するかを制限するために使用することができます ( メソッド例 ) またはアクセッサシグネチャ ( アクセサー例 ) にデコレータを置くことができます。

例 - 引数付き (デコレータファクトリー)

引数を使用する場合は、デコレータのパラメータを含む関数を宣言し、引数なしの例のシグネチャを持つ関数を返す必要があります。

class MyClass {
    @enumerable(false)
    get prop() {
        return true;
    }
}

function enumerable(isEnumerable: boolean) {
    return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) => {
        descriptor.enumerable = isEnumerable;
        return descriptor;
    };
}


静的メソッドデコレーター

メソッド・デコレーターに似ていますが、いくつかの違いがあります。

  • その target パラメータはコンストラクタ関数そのものであり、プロトタイプではありません。
  • 記述子はプロトタイプではなく、コンストラクタ関数に定義されます。

クラス デコレーター

@isTestable
class MyClass {}

実装パラメータです。

  • target : デコレータが宣言されているクラス ( TFunction extends Function ).

使用例 : メタデータapiを使用して、クラスの情報を保存します。


プロパティデコレーター

class MyClass {
    @serialize
    name: string;
}

実装パラメータです。

  • target : クラスのプロトタイプ( Object ).
  • propertyKey : プロパティの名前 ( string | symbol ).

使用例 : を作成する @serialize("serializedName") デコレータを使用し、そのプロパティ名をシリアライズするプロパティのリストに追加します。


パラメータ・デコレータ

class MyClass {
    myMethod(@myDecorator myParameter: string) {}
}

実装パラメータです。

  • target : クラスのプロトタイプ( Function -だそうです Function はもう機能しません。そのため any または Object をここに追加すると、任意のクラスでデコレータを使用できるようになります。あるいは、制限したいクラスの種類を指定します)。
  • propertyKey : メソッドの名前 ( string | symbol ).
  • parameterIndex : 関数のパラメータリストにおけるパラメータのインデックス( number ).

簡単な例

詳細な例(s)