📝

JavaScript Decorators

2021/07/04に公開

JavaScript, TypeScript 界隈における Decorators について取り上げます。

JavaScript と Decorators

JavaScript では馴染みのなかった Decorators が目に触れるようになったのは AtScript 発表の際だったと記憶しています。

AtScript

AtScript とは、2014 年 10 月 23 日、ng-europeにて発表された TypeScript を包含する「新構文」です。

このときの例文を引用します。

@Directive({
  selector: ["[blink]"],
})
class Blink {
  constructor(element: Element, options: Options, timeout: Timeout) {
    var selectors: Array<CssSelectors> = someThirdPartyAPI();
    element.query(selectors.join(",")).forEach((e) => options.apply(e));
  }
}

@Directive()という箇所が彼らのいう(当初いっていた)AtScript に該当する構文であり、本稿の題材でもある Decorators です。

筆者の確認できた限りでは、この構文を用いられた JavaScript ソースが公になったのは 2014 年 9 月 26 日のangular/angularにおけるコミットが初で、この時点ではまだ関連ソースも揃ってなく動作しないソースでした。Angular 2 関連で範囲を広げると、さらに前の 2014 年 9 月 3 日には Angular 2 に Decorators を採り入れる案があったようです。

ng-europe での発表に向けて、既にこの時期には動き出していたことが推察できます。

TypeScript

2015 年 3 月 5 日ng-confにて、Microsoft のJonathan Turner氏によって TypeScript 1.5 に Annotations が加わると発表されました。

翌 3 月 6 日にも同氏によってTypeScript と Angular 2 に関する講演が行われており、公式 Twitter でも以下のような発言が掲載されています。

<blockquote class="twitter-tweet" lang="en"><p>AtScript is Typescript <a href="https://twitter.com/hashtag/ngconf?src=hash">#ngconf</a></p>— ng-conf (@ngconf) <a href="https://twitter.com/ngconf/status/573521849780305920">March 5, 2015</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

事実上 AtScript は TypeScript 言語仕様として落ち着いたという瞬間です。(追記、稿末に詳細あり)落ち着こうとしています。

その後、2015 年 3 月 27 日に Microsoft よりTypeScript 1.5 Alphaの公式発表がなされ、予告されていた Decorators も併せてこの場で発表となりました。なお 1.0 以降、アルファ段階の TypeScript が公式発表として取り上げられたのはこれが初です。

Decorators の文化的背景

筆者には馴染みのない構文だったため、そもそもこういった@で書き始める構文はどの言語から影響を受けたのか、という疑問がありました。元となった言語の使用者ではないため表面的な事実の羅列となりますが、確認した限りを並べてみます。

C#

C#には、@の構文ではありませんがMetadata 構文というものがあります。登場時期は C# 1.0 と同じく 2001 年 2 月。深くは言及しませんが、メタデータを読み取るための Reflection という概念が Angular 2 の実装内にも確認できたため触れておきます。

Java

どうやら@で書き始めるこの構文の根元は Java にあるようです。2004 年 9 月 30 日に発表された J2SE 5.0 に採用されたMetadata 構文(アノテーション構文とも)が最初で、この機能も、Java 最初期(1996 年 1 月 23 日)から存在していた Javadoc の@が由来で採用された経緯があるようです。

J2SE 5.0(別名は Tiger で、現在は 2 番目のベータ・リリースです)が入手できるようになるまでは、コアとしての Java 言語でメタデータ機能に最も近いものは Javadoc による手法でした。
http://www.ibm.com/developerworks/jp/java/library/j-annotate1/

@構文は Java 由来なようですが、概念自体は前述の C#が先行しており、影響を与え合っていたと見る向きもあります。

Python

Python は 2004 年 11 月 30 日の 2.4 から@で記述するDecorators構文を備えました。これは PEP (Python Enhancement Proposals)で提言されたPEP 318 - Decorators for Functions and Methodsが源流のようです。資料には Java の影響を受けた旨が明記されています。

Why @?
There is some history in Java using @ initially as a marker in Javadoc comments and later in Java 1.5 for annotations, which are similar to Python decorators.
https://www.python.org/dev/peps/pep-0318/#why

Decorators は、やはり GoF のDecorator パターンが由来で、Java の Metadata 構文を用途までそっくり取り込んだわけではないようです。

Some symbol options:
@

  • Java-like, so not completely unknown.
  • Not confusable with any current Python symbol
  • Makes syntax highlighting easy

@採用の経緯に Java 風で既知の表記法だ、という旨が盛り込まれていました。PEP 318 がまとまっていった様子の議事録はとても興味深いものです。PythonDecoratorLibraryというコンテンツは、JavaScript において Decorators を用いる際の着想として参考になるかもしれません。

Dart

Dart(2011 年 10 月登場、2014 年 6 月にECMA-408として規格化)にもMetadata 構文と呼ばれる構文が存在しており、これは Java, Python のように@で始まっています。登場時期からみても、Dart はこれら先行言語からの影響を受けている可能性が高いです。

JavaScript に Decorators が持ち込まれた経緯

これまで存在しなかった Decorators 構文がなぜここへ来て JavaScript に採り入れられるのか、客観的事実を元にした推察です。

2013 年 10 月 AngularDart の存在

AngularDartの初期リリースはタグ基準で2013 年 10 月 17 日の v0.0.2です。AngularDart ではDart の言語仕様をそのまま活用して@で始まる Annotations を採用しています

AngularJS 1.x を Dart で再実装するとして動いていたようですが、Angular 2 が AngularJS 2, AngularDart 2 という名前ではなく"Angular 2 for JavaScript|Dart"となったことから一本化されたものと理解しています。事実、Angular 2 には.es6.dartという二つの拡張子のソースがまとめて格納されており、一つのプロジェクトで 2 言語に対応しようと試みられています。

Google のMiško Hevery氏がAngularDart の立ち上げ人で最多コード記述者である点、Angular 2 草案リポジトリの中心人物である点、ng-europe での AtScript の発表者が同氏である点から総合的に判断して、Angular 2 for JavaScript に Decorators が持ち込まれた経緯が AngularDart 由来である、そして主要人物が Miško Hevery 氏であることが分かります。

2014 年 4 月 TC39 での議題に上る

TC39 という ECMA のミーティングがあるのですが、TC39 自体については日本国内でもウォッチしている方がおられるので、そちらに任せます。(参考

2014 年 4 月の TC39で、"ECMA-262 7th Edition"、俗にいう ES7 の議論の際にYehuda Katz (wycats)氏によって案が提出されていたようです。

時系列としてはこの位置ですが、wycats 氏が Angular 事情と絡んでいたかは定かでなく、活動内容を見る限りその可能性は無さそうに見えます。TC39 にて草案が提出されたことを Angular 開発陣が観察していた可能性は有り得ます。

2014 年 10 月 AtScript の発表

前述のとおり、ng-europe にて AtScript の発表が行われました。まだこの時は Google 側の独自的な構文の範疇でしたが、ここから約半年で大きく動くことになります。

2015 年 3 月 TypeScript 1.5 への採用

さすがに Google と Microsoft 間のやりとりは窺い知れませんが、AtScript 絡みで情報交換はしていたのだろうと想像しています。MSDN Blogs では大歓迎の模様です。

この発表を行った Microsoft のJonathan Turner氏は 2015 年 3 月 29 日に Decorators に関するTC39 Proposalを立ち上げている件が非常に興味深く、ここに参加しているRon Buckton氏は TypeScript 開発者の一人です。

Decorators の ECMA-262 7th Edition での規格化

語弊を含んで噛み砕いて言うと『JavaScript ES7 での Decorators の仕様策定』です。前述のとおり TC39 ミーティングで進んでいるようです。

2015 年 3 月の TC39ではwycats 氏のプロポーザルで議論が進んだようですが、Microsoft 側もプロポーザルを準備しており、今後どのように絡んでくるのか非常に注目しています。

TypeScript 側のプロポーザル

Babel

ES6, ES7 Proposal の構文を ES5 に変換することでおなじみのBabelにはDecorators がすでに実装されています

この Babel の実装根拠が wycats 氏のプロポーザルに限っているため、Angular 2 が Babel で動かないという問題が起こりました。Angular, Microsoft 側からも動きが出ると予想しており、動きにあわせて Issue も立つことでしょうから、この問題は時間が解決すると期待しています。

現時点での実装と挙動

挙動に関して本稿で触れると冗長になるため今回は割愛します。この件については Qiita やその周辺にて以下の記事を確認しています。(敬称略)

2015 年 4 月 13 日現在、Babel と TypeScript で挙動に差がでているという目撃情報があるので、これも時期尚早という印象がありました。
(追記)執筆中に直っていたことに気付いていませんでした。Babel 開発者のsebmck氏が日本(上記記事絡みの方々)での挙動指摘のツイートを検索・翻訳し、直してしまったようです。恐るべき情報収集力と速さに感服しました。

AtScript は TypeScript を包含しているという誤解

(追記)本稿掲載後、さらに延長線上を調査していたところ、AtScript 構文と TypeScript に完全な互換性が無いことが明らかになりました。TypeScript 1.5 Alpha のtscでどうやっても通らないこの構文が許容されている根拠は何かと調べていたところ、次の二つの Issues/PRs を発見しました。

これらが意味するところを突き止めるためコミットの前後を追っていたところ、この構文は/tools/transpilerのツールのみが処理できるようで、ここを深追いはしていませんが traceur のランタイムを拡張して実現させているようでした。

つまり変換できない Babel、TypeScript 1.5 Alpha 側に問題があるのではなく、Angular 2 の独自実装構文が生き残っていたということになります。ng-conf ではまことしやかに「AtScript は TypeScript だ」と囁かれ筆者も当然そうなのだろうと信じていたのですが、Angular 2 側は 2015 年 4 月現在、TypeScript にまだ移行できておらず、TypeScript 言語仕様に加えてもらうのか、この構文を Angular 側が諦めるのか、traceur 依存を続けるのか、まったく目が離せない状況です。ng-europe から ng-conf までの約半年に前述した invalid 構文についても仕様策定しておけば…と些か片手落ち感があります。

まとめ

  • @をデコレーション、アノテーションの構文として使う言語は Java, Python, Dart など複数
  • AngularDart では Dart 言語にある@を使用している
  • Angular 2 で JavaScript 版と Dart 版を同時開発する上で JavaScript に Decorators を持ち込んだ(発表当初の AtScript)
    • 2015 年 3 月 5 日、TypeScript 1.5 に Decorators を採用すると告知
    • 2015 年 3 月 27 日、TypeScript 1.5 Alpha にて Decorators が正式に発表
  • TC39 にて ES7 規格化の動き
    • プロポーザル提出は wycats 氏のみだが TypeScript 側にも準備がある

主要人物

敬称略

関連記事

謝辞

本稿の作成中、多くの方々を巻き込んでしまい、多大なる学びが得られました。ありがとうございました。お騒がせいたしました。

感想

まだ早い。

Discussion