[[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)