そういえば少し前の TypeScript 5.0 から Stage3 のデコレーターがフラグ無しで使えるようになったと聞きます
あまり使うつもりも無かったのと ステージが上がるのが長期的なものだったので詳しくは見てなかったですが Stage3 に上がって 1 年以上経ってるようですし TypeScript で標準でつかえるようになるということは現状の機能で JavaScript に来そうですし どんなものか見てみました
クラス専用機能みたいです
思ってたのと違う
なんか前もそんなことを言ったような気がします
クラス定義やメソッド定義の前にだけかけるようです
また 単純に関数で変換するだけでなく コンテキストオブジェクトも受け取って 初期化処理を追加するなど思ってたより複雑なものでした
const decorator = (method, context) => {
console.log(context)
context.addInitializer(function() {
console.log(this)
})
}
addInitializer はクラスのデコレーターだと クラス定義後すぐで メソッドだと各コンストラクタ内の処理として呼び出されるようです
また this を受け取るのでアロー関数ではない通常の関数を渡す必要があります
また デコレーターは値を返すことは必須ではなく 返さないとデコレーターの引数に渡されるものそのままがセットされるようです
期待してたのは もっと単純で任意の式の前におくことができてアロー関数にも適用できるものだったのですけどね
こんなこともできて 関数でラップする代わりの記法みたいなもの
const log = fn => (...a) => {
console.log("called", fn, a)
const result = fn(...a)
console.log("result", fn, result)
return result
}
const fn = @log (a, b) => a + b
fn(1, 2)
// called (a, b) => a + b [1, 2]
// result (a, b) => a + b 3
const plus1 = x => x + 1
console.log(@plus1 10)
// 11
関数でラップすればいいだけ といえばそうなのですが これができたほうが見やすく書けると思うのですよね
例えば setTimeout みたいに関数を渡すところ
setTimeout(
() => {
console.log(1)
},
1000
)
これを関数でラップすると
setTimeout(
deco(option1, option2, () => {
console.log(1)
}),
1000
)
デコレーターで書けると
setTimeout(
@deco(option1, option2)
() => {
console.log(1)
},
1000
)
明らかにこっちのほうがいいと思います
手前に書く記法でもいい感じです
foo(
value1,
value2,
@once (value) => {
console.log(value)
},
)
ただ 構文を考えると アロー関数の引数の () がデコレーターの once の関数呼び出しみたいになり 判断できなそうです
対処するなら関数を () で包まないとダメそうで そうなるなら求めてるものじゃないんですよね
この記法ではないものの 拡張機能として将来的もっと色々な使い方が考えられているようです
便利というより複雑という印象が強いですけど
https://github.com/tc39/proposal-decorators/blob/master/EXTENSIONS.md