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つ(
ClassDecorator | PropertyDecorator | MethodDecorator | ParameterDecorator
)に割り当て可能です。- 装飾された値に代入可能な値(クラスデコレータとメソッドデコレータの場合)を返します。
実装パラメータ
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"]
戻り値は以下のとおりです。Message - testing
ノート:
this
のコンテキストは、インスタンスのインスタンスにはなりません@enumerable(false)
と@log
のようなものを同時に使うことができます(例: 悪い vs 良い )TypedPropertyDescriptor
のtype引数は、どのメソッドシグネチャ( メソッド例 )またはアクセサシグネチャ( - )を制限するために使用できます。 アクセサ例 )デコレータをつけることができます。引数を使用するときは、デコレータのパラメータで関数を宣言してから、引数なしで例のシグネチャを持つ関数を返す必要があります。
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
)。他の答えでは見られない重要なことが1つあります。
デコレータを宣言に適用する方法をカスタマイズしたい場合は、デコレータファクトリを書くことができます。デコレータファクトリは、実行時にデコレータによって呼び出される式を返す関数です。
// This is a factory, returns one of ClassDecorator,
// PropertyDecorator, MethodDecorator, ParameterDecorator
function Entity(discriminator: string): {
return function(target) {
// this is the decorator, in this case ClassDecorator.
}
}
@Entity("cust")
export class MyCustomer { ... }
TypeScriptハンドブック デコレータの章 を確認してください。
class Foo {
@consoleLogger
Boo(name:string) { return "Hello, " + name }
}
コンソールへの各呼び出しをログに記録するようなものを実装することができます。
function consoleLogger(target: Function, key:string, value:any)
{
return value: (...args: any[]) =>
{
var a = args.map(a => JSON.stringify(a)).join();
var result = value.value.apply(this, args);
var r = JSON.stringify(result);
console.log('called method' + key + ' with args ' + a + ' returned result ' + r);
return result;
}
}