Node.jsアドベントカレンダーの記事です。
JavaScript本体の仕様策定でなかなかステージ3にあがらないデコレータ。
TypeScriptには--experimentalDecorators
オプションが必要ですが、以前から実装されています。この場合にのみメタデータが扱えるようになっています。
メタデータのプリミティブな使い方を書いておきます。greetingメソッドにメタデータを付与します。それを実行時に取り出して表示しています。
import "reflect-metadata";
class A {
@Reflect.metadata("metadata-key-dayo", "hello world")
greeting() {
const message = Reflect.getMetadata("metadata-key-dayo", this, "greeting");
console.log(message);
}
}
const a = new A();
a.method();
// hello world
どんな値でも入れられる便利な箱となっています。
--emitDecoratorMetadata
オプションをつけると、TypeScriptは次のようなコードを生成します。
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
__decorate([
Reflect.metadata("metadata-key-dayo", "hello world"),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], A.prototype, "method", null);
このreflect-metadataパッケージを使ったコードです。細かいところを省くと、上記のサンプルのようなメタデータが自動で追加されます。それには"design:type"と、"design:parameters"と"design:returntype"というキーでもろもろの情報が付与されることがわかります。フィールドデコレータがついた場合は"design:type"だけで、クラスには特に追加のメタデータは付与されません。
最初のサンプルはメソッドの中で情報を取得しましたが、そのインスタンスメソッドの中でも外でも、同じようにこれらの情報にアクセスできます。
console.log("🐙", Reflect.getMetadata("design:type", a, "method"));
console.log("🐙", Reflect.getMetadata("design:paramtypes", a, "method"));
console.log("🐙", Reflect.getMetadata("design:returntype", a, "method"));
これらのメタデータは、あくまでも「なにかしらのメタデータが付与されたフィールド、クラス」に対する追加情報ですので、なにもデコレータが付いていなかった要素は型情報も取得できない点に注意です。
面白そうですよね?JSONからのシリアライズで型チェックをしながらクラスのフィールドに値を入れていくとかできそうですよね?
今までどういうものか調べようと思っていてずっと先延ばしにしていたのですが、ちょうどNode.jsアドベントカレンダーが空いていたので軽く調べて書いてみました。
詳しくはこちらに書いてあります。