2025-04 の TC39 meeting
まとめ
Agenda: https://github.com/tc39/agendas/blob/main/2025/04.md
速報: https://x.com/robpalmer2/status/1912967475551146073
Note: https://github.com/tc39/notes/blob/main/meetings/2025-04
決まったこと
Web compatibility issues / Needs Consensus PRs
Normative: add notation to PluralRules (ecma402#989, slides) | Ujjwal Sharma
複数形を扱う Intl.PluralRules に Intl.NumberFormat にもある "notation" オプションを追加する話。
ICU に入ったため、それが ECMAScript にも降りてきた形。
https://unicode-org.atlassian.net/browse/ICU-13836
Normative: Mark sync module evaluation promise as handled (#3535, slides) | Nicolò Ribaudo
(JSON や CSS のような)非 Cyclic Module Records において、モジュールの読み込みに失敗し Promise がリジェクトされたときに Unhandled Rejection を起こしてしまう仕様バグの修正。
仕様上同期モジュールであっても Promise を生成するが、それがリジェクトされたかどうかは無視するのが正しい。
Stage 4 (ES2026)
N/A
Stage 3
Note about changed behavior of Array.fromAsync after landing #2600 | Kevin Gibbons
以前話されていた AsyncFromSyncIterator でイテレーターが閉じられた際に元の Iterator に伝播されていなかったのを修正する Normative Change。
今までは for-await-of でしか使われない仕様だったが Array.fromAsync にも使われることになることから再確認された。
Temporal status update (slides) | Philip Chimento
Firefox Nightly に搭載された。
Temporal はマイクロ秒を扱う BigInt API を持っているが 75 bit で事足りるため binary64 のペアで実装するのがパフォーマンス的に良いという話がされている。
Explicit Resource Management implementer feedback (slides) | Daniel Minor
switch-case の中でスコープを作らずに使用できると予期せぬ動作を引き起こしてしまうということで、SyntaxError にするかどうかが議論され、承認された。
https://gyazo.com/5d11e3f6fce3de4b6e5a5e6a5de0492e
Stage 2.7
Immutable ArrayBuffer for stage 3 (keynote slides, pdf slides, incomplete video) | Mark Miller, Peter Hoddie
Test262 レビュー中。
Upsert for stage 2.7 (slides) | Daniel Minor
Map#getOrInsert{,Computed} の提案。Stage 2.7 になった。
Non-extensible Applies to Private for stage 1, 2, or 2.7 (keynote slides, pdf slides, video) | Mark Miller, Shu-yu Guo
Stage 1 Stablilize Integrity で以前話されたが、Non-extensible Object に対して Private Fields を付与できる問題がある(The return override-mistake)。
code: js
class NonExtensibleBase {
constructor() {
Object.preventExtensions(this);
}
}
class ClassWithPrivateField extends NonExtensibleBase {
#val;
constructor(v) {
super();
this.#val = v;
}
}
new ClassWithPrivateField(42); // doesn't throw
これは PrivateFieldAdd と PrivateMethodOrAccessorAdd にバリデーションを追加することで解決することができる。
https://gyazo.com/9ab5ab8a6eb053fe420ff1f79f5bfa52
Chrome が調査したところ、この変更によって影響を受けるサイトは 0.000011% で Web 互換性的に大丈夫そう。
https://github.com/syg/proposal-nonextensible-applies-to-private/issues/1
別の提案として Stage 2.7 になった。
Stage 2
Intl Era Month Code Stage 2 Update (Slides) | Shane F Carr
Intl に Temporal の暦を入れる提案。ヒジュラ暦が太陰暦なため実装が大変らしい。
AsyncContext Stage 2 Update (slides) | Andreu Botella, Chengzhong Wu, Nicolò Ribaudo
ブラウザのフィードバックで Mozilla から EventTarget で明示的に removeEventListener されていないハンドラーがあったときに、今までより多くのメモリリークを起こしてしまう懸念が示された。これを解決するためにイベントハンドラーではなく、イベント発火点から伝播するように変更された。
Mozilla は実装の労力に見合わないと懸念しており、Chrome はユースケースの価値を認めている状況。
export defer extracted from import defer: stage 2 update or for stage 1 (slides) | Nicolò Ribaudo
export defer が import defer の提案からスプリットされ、Stage 2 になった。
Stage 1
Don't Remember Panicking stage 1 Update (keynote slides, pdf slides, video) | Mark Miller, Peter Hoddie
即座にコードの実行を止める API の提案。トランザクションの整合性が重要なシステムに必要になるらしい。HostFaultHandler フックについては肯定的だが、Reflect.panic については否定的。
Stage 1 update for decimal & measure: Amounts (slides) | Jesse Alama
前回の会議で Decimal と Measure を統合する話があったが、そのまま分かれたまま進むこととなっていた。今回は新たに精度付き数値を扱うクラス(Decimal.Something/Amount)を追加したいという話が出ている。
https://gyazo.com/13d796cebcce42b3f93084080837798c
この新しいクラスが入ることになった場合 Intl.NumberFormat や Intl.PluralRules で受け入れるようになる。次回の会議で Stage 2 になるかもしれない。
Compare Strings by Codepoint for stage 1 (docs slides, pdf slides) | Mathieu Hofman, Mark Miller
文字列をコードポイントベースで比較するメソッドの提案。SQLite などで使うとのこと。
code: js
const arr = [
'\u{ff42}', // Fullwidth Latin Small Letter B
'\u{1d5ba}', // Mathematical Sans-Serif Small A
'\u{63}', // Latin Small Letter C
];
console.log('native compare', ...arr.sort()); // 'c', '𝖺', 'b'
console.log('locale compare', ...arr.sort((a, b) => a.localeCompare(b))); // '𝖺', 'b', 'c'
console.log('null locale compare', ...arr.sort(new Intl.Collator('zxx').compare)); // '𝖺', 'b', 'c'
console.log('codepoint compare', ...arr.sort(String.codePointCompare)); // 'c', 'b', '𝖺'
Stage 1 になった。
Object.propertyCount for stage 1 or 2 | Jordan Harband
オブジェクトのプロパティ数を取得する API がないため、Object.keys(obj).length が広く使われているがこれはパフォーマンスがよくない。そこで Object.propertyCount を追加する提案。
enumerable や Symbol をカウントするかどうかを指定するオプションを入れるらしい(デフォルトは Object.keys と同じ)。
code: ts
type KeyType = "index" | "nonIndexString" | "symbol";
interface ObjectPropertyCountOptions {
keyTypes?: KeyType[] | undefined;
enumerable?: boolean | "all" | undefined;
}
Stage 1 になった。
Composites for stage 1 (repo, slides) | Ashley Claymore
Records & Tuples の提案で新しいプリミティブを追加することが難しいと判明したため、Composites で新たにオブジェクトを追加する提案として進めていく。
code: js
const pos1 = Composite({ x: 1, y: 4 });
const pos2 = Composite({ x: 1, y: 4 });
Composite.equal(pos1, pos2); // true
const positions = new Set(); // the standard ES Set
positions.add(pos1);
positions.has(pos2); // true
Composite は凍結されるが、中に持つオブジェクトはそのままとなる。
code: js
const date = new Date();
const composite = new Composite({ date });
Object.isFrozen(composite); // true
composite.date === date; // true
比較をどうするか議論中。
https://github.com/tc39/proposal-composites/issues/15
Stage 1 となった。
Enums for Stage 1 (explainer, slides) | Ron Buckton
Enums が TypeScript 互換なシンタックスで提案された。
code: ts
enum Numbers {
zero = 0,
one = 1,
two = 2,
three = 3,
alsoThree = three // self reference
}
今のところ TypeScript と違って値が自動で入らないようになっている(auto を使った別のシンタックスで入れることになるかもしれない)。Stage 1 になった。
Disposable AsyncContext.Variable for Stage 1 (slides) | Chengzhong Wu, Luca Casonato, snek
AsyncContext.Variable の提案は現状 run メソッドでスコープを作る必要がある。これにより函数を新たに AsyncContext でラップする場合に変更するコードが多くなってしまう。
code: js
function* gen() {
yield 1;
yield 2;
}
// ↓
const asyncVar = new AsyncContext.Variable();
function* gen() {
const span = createSpan();
yield* asyncVar.run(span, function *() {
yield 1;
yield 2;
});
}
そこで Symbol.dispose メソッドを付与し、using を使って簡単に追加できるようにする提案。
code: js
const asyncVar = new AsyncContext.Variable();
function* gen() {
using _ = asyncVar.withValue(createSpan());
yield 1;
yield 2;
}
Stage 1 になった。
Stage 0
N/A
Withdrown
Withdrawing Record & Tuples (slides) | Ashley Claymore
Stage 1 Composites を進めることとなり廃止。
その他
WHATWG Observables for general TC39 feedback (slides) | Dominic Farolino
WebKit が Standards Positions で、TC39 会議でフィードバックを受けるよう要請していたため議題に出た。
https://github.com/WebKit/standards-positions/issues/292#issuecomment-2682983190
Observable については Zenn に記事を書いている。
https://zenn.dev/pixiv/articles/471a8cf864d35f
Guidelines for Locale-Sensitive Testing in Test262 (slides) | Philip Chimento
Test262 に Locale-Sensitive なテストが入ると困る話。
Update to Consensus policy (slides) | Michael Saboff
TC39 の合意形成プロセスについて。単独反対者が提案をブロックするにはもうひとり別会社の支持者を必要とするなどの案が出たが保留。
総括
Records & Tuples が廃止され、新たに Stage 1 Composites に置き換わった。
今回は Stage 1 が多く、特に TypeScript から Enum を ECMAScript に入れようとする流れは興味深く思う。
#ECMAScript