[[TypeScript 5.2]]で[[Decorator Metadata]]という仕様に対応されたので試してみた。 ## 背景 [[Decorator Metadata]]を参照。 ## 仕様の概要 - `ClassFieldDecoratorContext`に`metadata`が追加されている - `metadata`には`Class[Symbol.metadata]`の形でアクセス可能 ## 動作確認 まずは[[デコレーター (JavaScript)]]について、フィールドデコレーターを使ってみる。 ```ts function Transform(args?: { upper?: boolean; lower?: boolean }) { return function (target: undefined, context: ClassFieldDecoratorContext) { return function (this: Color, v: string) { if (args?.upper) { return v.toUpperCase(); } if (args?.lower) { return v.toLowerCase(); } return v; }; }; } class Color { @Transform({ upper: true }) first: string = "First"; @Transform({ lower: true }) last: string = "Last"; } const c = new Color(); console.log(c); ``` ```console Color { first: 'FIRST', last: 'last' } ``` ## metadataをセットしてみる ```ts // polyfill for Symbol.metadata (Symbol as any).metadata ??= Symbol("Symbol.metadata"); function Transform(args?: { upper?: boolean; lower?: boolean }) { return function (target: undefined, context: ClassFieldDecoratorContext) { return function (this: Color, v: string) { context.metadata[context.name] = args; if (args?.upper) { return v.toUpperCase(); } if (args?.lower) { return v.toLowerCase(); } return v; }; }; } class Color { name: string = "Sample"; @Transform({ upper: true }) first: string = "First"; @Transform({ lower: true }) last: string = "Last"; } const c = new Color(); console.log(c); console.log(Color[Symbol.metadata]); ``` ```console Color { name: 'Sample', first: 'FIRST', last: 'last' } [Object: null prototype] { first: { upper: true }, last: { lower: true } } ``` ### polyfillがないと動かない #2023/09/03 時点ではほとんどのランタイムで[[Symbol.metadata]]に対応していないため、実行時に`context.metadata`や`Color[Symbol.metadata]`は`undefined`になってしまう。 ```error context.metadata[context.name] = args; ^ TypeError: Cannot set properties of undefined (setting 'first') ``` 最初の2行はそれを回避するための実装。 ```ts // polyfill for Symbol.metadata (Symbol as any).metadata ??= Symbol("Symbol.metadata"); ``` [[TSConfig]]の[[lib (tsconfig)|lib]]はあくまで型定義(ビルド)時の話であるため、[[ランタイム]]のフォローも忘れずに。 ## 参考 - [TypeScript v5\.2で導入されるusing宣言とDecorator Metadataを使ってみる \| 豆蔵デベロッパーサイト](https://developer.mamezou-tech.com/blogs/2023/07/19/typescript-5-2-intro/) - [ECMAScript Decorators の変遷と最新仕様 \- Qiita](https://qiita.com/petamoriken/items/b081f50b30d73275c801#%E6%9C%80%E7%B5%82%E7%9A%84%E3%81%AA%E6%8F%90%E6%A1%882020%E5%B9%B48%E6%9C%88) - ["undefined" passed for the "context\.metadata" field in a decorator metadata · Issue \#55453 · microsoft/TypeScript](https://github.com/microsoft/TypeScript/issues/55453)