Ecmascript proposal report 2021春
Ecmascriptの現在議論中の仕様について、執筆時点で自分が気になってるものをまとめてみました。
Ecmascriptの仕様策定
そもそもEcmascriptってどうやって仕様決めてるのか?というところなんですが、Ecmascriptの仕様はTC39 という組織(さらにいえば、TC39はecma internationalという組織のうちの1つ)によって管理されています。
Ecmascriptの新しい仕様は、TC39のproposals(提案)リポジトリで管理されており、以下のStageという段階に分けられます。
stage | overview | detail |
---|---|---|
stage0 | Strawperson | アイディア段階、やりたきことを議論 |
stage1 | Proposal | 提案ドキュメントとしてまとまってる状態 |
stage2 | Draft | 仕様書の初期ドキュメントがまとまってる状態 |
stage3 | Candidate | ブラウザの実装待ち |
stage4 | Finished | 仕様策定完了 |
ここからは僕が気になってるProposalを独断と偏見でまとめていきます。
※Propsalの一覧はこちら から。
Import Assertions(Staeg3)
syntax
// importの最後に`assert { type: "json" }`を追加
import json from "./foo.json" assert { type: "json" };
import("foo.json", { assert: { type: "json" } });
概要
いわゆるCSS Modulesなどのように、JS以外も標準でimportできるようにしていきたいよねというSynthetic Modulesと呼ばれる機能実装の一貫で出てきたファイル検証の構文とJSONのimport。
importする際にMIMEだけで拡張子判断することは、サーバー側が予期せず異なるMIMEを提供した場合、管理者やユーザーにとって予期せぬコードの実行が行われる可能性もあるのでセキリティ的によくないということになり、その結果、MIME+利用者側でimportするファイルがなんなのか判断する必要ありとなり、このimport assertionが提案されました。
拡張子で判断できるのでは?と思ったんですが、Web上においてリクエストURLの末尾拡張子=解釈方法ではない、というこれまでの原則に則ると成り立たない(ex: .cssって拡張子がリクエストに入ってなくても実際にはCSSが帰ってくるかもしれない)とのことでした。ついwebpack前提で考えてしまいますが、ブラウザからimportされることを考えると納得ですね。
今後の影響
このPropsalにより、今後JS以外の拡張子のimportが標準仕様となっていく動きが強まっていくと思われます。これは既存のCSS modulesなどと微妙に仕様が異なるとか、css-loaderとbabelどっちでどういう責務分けをするのかとかの議論につながっていくと思われ、トランスパイラ・コンパイラを利用している我々にも何かしらの影響が出てくるかもしれません。
Record&Tuple(Stage2)
syntax
// Objectや配列の宣言に`#`を足して`#{}`, `#[]`で宣言
const proposal = #{
id: 1234,
title: "Record & Tuple proposal",
contents: `...`,
// tuples are primitive types so you can put them in records:
keywords: #["ecma", "tc39", "proposal", "record", "tuple"],
};
const measures = #[42, 12, 67, "measure error: foo happened"];
概要
immutableJS に代表されるようなImmutableなデータ構造を標準としてサポートしようというProposalです。
通常のObjectや配列とほぼ同じですが、以下2つの大きな特徴を持ってます。
- deeply immutable(Mutableな要素は含められない)
- 比較が参照ではなくなる(下記参考)
assert(#{ a: 1 } === #{ a: 1 }); // true
assert(#[1, 2] === #[1, 2]); // ture
ただし、immutableJSのように.set()/.get()
のようなメソッドは持っていません。
今後の影響
TypescriptでDeepReadonly<T>
とか作って書いてた自分としては普通に嬉しいし、
immutablityと同時に参照を気にしなきゃいけないReduxないしReactとかは結構恩恵あるかもって思ったりしてます。
エコシステム目線で言うと、これをTypescriptがサポートするのはそこまで難しくない気がします(readonly
あるし)が、babelやprettierがどこまでやるのか次第ではちょっと大変そうにも思えます。
代入しようとしてもSyntaxErrorではなく、TypeErrorっぽいからそこまで難しくないのかな・・・
Temporal(Stage2)
syntax
Temporal.now.instant()
// 2021-01-13T20:57:01.500944804Z
const date = Temporal.PlainDate.from({year: 2006, month: 8, day: 24}); // => 2006-08-24
date.year // => 2006
date.inLeapYear // => false
date.toString() // => "2006-08-24"
概要
JSでは日時を扱うDate
Objectがややこしく忌み嫌われてきて、moment
やdayjs
、date-fns
などの日時を扱いやすくするためのライブラリがいくつか登場してきました。
こういった状況を標準としても打破すべきとして登場したのがTemporal
です。なぜこんなややこしい名前なんだろうと個人的には思いますが、まぁ確かにDateって命名は使われてるし、日付を扱うとはいえ前回のものとは全く異なるAPIなので命名難しいところですね。
Temporal
はこれまでのDate
と異なり、以下のような特徴を持っています。
- immutable
- タイムゾーンを意識しなくて済むPlainな扱いやdurationなどの扱いが可能
- nowとして取得できるのがシステムの完全にタイムゾーン由来
今後の影響
その他細かいメソッドや内包Objectについては省略しましたが、Temporal
の登場によってJSの日時計算処理系にライブラリの導入が実質必須みたいな状態から抜けられるんじゃないでしょうか。
※その他の詳細なAPIの仕様はこちらを参照ください。
do expressions(Stage1)
syntax
// do expression
let x = do {
let tmp = f();
tmp * tmp + 1 // 最後の評価がxに代入される
};
// in jsx
return (
<nav>
<Home />
{
do {
if (loggedIn) {
<LogoutButton />
} else {
<LoginButton />
}
}
}
</nav>
)
// async do
async do {
await readFile('in.txt');
let query = await ask('???');
// etc
}
概要
ScalaやRustのように、ブロックの最後に評価した値を暗黙的に返します。
個人的にはJSにif式がないのは手続き型の助長にしかならないと思ってたので嬉しくはあるんですが、ちょっと冗長(特にasync doとかになるとちょっとややこしい)な気もしてて、結局欲しかったのってif式なのではって気もします。
とかいいつつ、実際出てきたらjsxで多用しそうですね。
Pipeline Operator(Stage1)
syntax
let person = { score: 25 };
let newScore = person.score
|> double
|> (_ => add(7, _))
|> (_ => boundScore(0, 100, _));
概要
F#やElmで馴染みのあるパイプラインオペレータです。現在、Syntaxについて絶賛議論中のとなってますが、初期提案から3年ほど立っており、実際stage2にいくのかこのままマージされず棄却されるのか不明ですが個人的には楽しみにしてるProposalなので期待も込めて挙げてみました。
どうやら問題はasyncをどう扱うかで、特殊なawaitを仕様にするかawait時だけシンタックスを変えるかなどいろいろ議論されているようです。
async抜きなら、似たようなことはlodash/flowで十分実装できるので、本当に標準サポートする必要があるかまでは正直懐疑的ですが、個人的な趣味嗜好としてはとても欲しいです。
Decorator(Stage2)
syntax
// exmaple1
@defineElement("my-class")
class C extends HTMLElement {
@reactive prop clicked = false;
}
// exmaple2
function logged(value, { kind, name }) {
if (kind === "method") {
return function (...args) {
console.log(`starting ${name} with arguments ${args.join(", ")}`);
const ret = value.call(this, ...args);
console.log(`ending ${name}`);
return ret;
};
}
}
class C {
@logged
m(arg) {}
}
new C().m(1);
// starting m with arguments 1
// ending m
概要
Typescriptなどに古くからあるDecoratorです。DecoratorのProposalは歴史が古く、5年以上議論されてきています。PHPでもattributeが採用され、Rustにもマクロという似たような機構があったりでこの辺は昨今の流行りな感もあります。
機能としてはまぁ普通にClassのデコレータですね(雑)。
今後の影響
TypescriptだとDecoratorはexperimentalだったと思うので、標準採用されれば利用者も増えそうですね。
Web ComponentsのcustomElements.define
とか個人的には面倒なんでこれでできると嬉しかったりします。
まとめ
まだまだ気になってるProposalはあるんですが、以外と調べてまとめるのが時間かかって大変だったので今回はこの辺までにしようと思います。
普段はJxckさんのmozaic.fmでこの辺の話を聞いてるんですが、やっぱり自分で調べ直すとかなり大変ですね、、、
近々やる気が維持できたら残りの気になってるProposalまとめるか、もしくはCSSの仕様策定に明るくないので、そっちをがんばってみようかと思います。
Discussion