Top ECMAScript Proposals Shaping the Future of JavaScript

This article surveys the most noteworthy ECMAScript proposals—from Record & Tuple and the .at() method to Temporal, private methods, top‑level await, import assertions, error cause, decorators, iterator helpers, throw expressions, upsert, observable, do‑expressions, pipeline operator, partial‑application syntax, and await.opts—explaining their purpose, current stage, and providing practical code examples.

Alibaba Terminal Technology
Alibaba Terminal Technology
Alibaba Terminal Technology
Top ECMAScript Proposals Shaping the Future of JavaScript

Recently, several intriguing ECMAScript proposals have emerged, such as Record & Tuple, throw expressions, and Error Cause, promising a new wave of JavaScript evolution. This article lists the proposals the author finds most worth following, covering new APIs, syntax changes, and their current TC39 stages.

Background

ECMA (European Computer Manufacturers Association) maintains standards like ECMAScript (ECMA‑262). TC39, the technical committee of ECMA, drives the evolution of JavaScript through five stages: strawman (stage 0), proposal (stage 1), draft (stage 2), candidate (stage 3), and finished (stage 4).

Record & Tuple (stage 2)

The proposal-record-tuple adds two immutable data structures—Record (object‑like) and Tuple (array‑like). Their members are compared by value, so identical Records or Tuples are === true.

const proposal = #{
  id: 1234,
  title: "Record & Tuple proposal",
  contents: `...`,
  keywords: #["ecma", "tc39", "proposal", "record", "tuple"]
};

const measures = #[42, 12, 67, "measure error: foo happened"];

.at() – Relative Indexing (stage 3)

Array.prototype.at()

and similar methods for strings and typed arrays allow negative indices to access elements from the end, simplifying code that previously required arr[arr.length‑1] or arr.slice(-N)[0].

const last = arr.at(-1); // same as arr[arr.length‑1]

Temporal (stage 3)

The proposal-temporal introduces a global Temporal namespace offering modern date‑time APIs, such as Temporal.Instant, Temporal.PlainDate, Temporal.PlainTime, and Temporal.Duration.

const instant = Temporal.Instant.from('1969-07-20T20:17Z');
const date = Temporal.PlainDate.from({year:2006, month:8, day:24});
const time = Temporal.PlainTime.from({hour:19, minute:39, second:9, millisecond:68, microsecond:346, nanosecond:205});
const duration = Temporal.Duration.from({hours:130, minutes:20});

Private Methods (stage 3)

The proposal-private-methods adds true private fields, methods, and accessors to JavaScript classes using the # syntax, independent of TypeScript’s private keyword.

class IncreasingCounter {
  #count = 0;
  get value() { console.log('Getting the current value!'); return this.#count; }
  increment() { this.#count++; }
}

Top‑level await (stage 4)

proposal-top-level-await

allows await to be used directly at the module’s top level without wrapping it in an async function, a feature already supported in Node 14.8+.

const data = await fetch('./data.json');

Import Assertions (stage 3)

With proposal-import-assertions, import statements can declare the expected module type, e.g., import json from "./foo.json" assert {type: "json"}, improving safety for JSON and other non‑script modules.

import json from "./foo.json" assert {type: "json"};
import("./foo.json", {assert: {type: "json"}});

Error Cause (stage 3)

The proposal-error-cause lets errors carry a cause property, enabling clearer propagation of underlying failures.

await fetch(url).catch(err => {
  throw new Error('Download failed', {cause: err});
});

Decorators (stage 2)

Decorators, now in their third draft, allow annotation of classes, methods, and fields. They are heavily used by frameworks like Angular, NestJS, and MidwayJS.

Decorator example
Decorator example

Iterator Helpers (stage 2)

proposal-iterator-helpers

adds utility methods to iterators, similar to Python’s itertools, enabling operations like filter directly on generator objects.

function* naturals() { let i = 0; while (true) { yield i++; } }
const evens = naturals().filter(n => n % 2 === 0);
for (const even of evens) console.log(even, 'is an even number');

Throw Expressions (stage 2)

With proposal-throw-expressions, throw can appear inside expressions, e.g.,

const encoder = encoding === "utf8" ? new UTF8Encoder() : throw new Error("Unsupported encoding")

, supporting expression‑oriented programming.

function getEncoder(encoding) {
  const encoder = encoding === "utf8" ? new UTF8Encoder()
                : encoding === "utf16le" ? new UTF16Encoder(false)
                : encoding === "utf16be" ? new UTF16Encoder(true)
                : throw new Error("Unsupported encoding");
}

Upsert (Map.prototype.emplace) (stage 2)

The proposal-upsert adds an emplace method to Map, inserting a new entry or updating an existing one in a single call.

myMap.emplace(key, value);

Observable (stage 1)

proposal-observable

brings RxJS‑style Observables to the language, introducing Observable, Observer, and related operators with lazy data emission.

function listen(element, eventName) {
  return new Observable(observer => {
    const handler = event => observer.next(event);
    element.addEventListener(eventName, handler, true);
    return () => element.removeEventListener(eventName, handler, true);
  });
}

Do Expressions (stage 1)

Similar to throw expressions, do { … } allows a block to produce a value, enabling more concise functional patterns.

let x = do { let tmp = f(); tmp * tmp + 1 };
let y = do { if (foo()) f(); else if (bar()) g(); else h() };

Pipeline Operator (stage 1)

The |> operator improves readability of chained function calls, turning exclaim(capitalize(doubleSay("hello"))) into a left‑to‑right pipeline.

let result = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

Partial Application Syntax (stage 1)

This proposal introduces a concise syntax for currying functions, using ? as a placeholder for arguments to be supplied later.

const addOne = add(1, ?);
const addTen = add(?, 10);
let newScore = person.score
  |> double
  |> add(7, ?)
  |> boundScore(0, 100, ?);

await.opts (stage 1)

proposal-await.opts

adds await.all, await.race, await.allSettled, and await.any as syntactic sugar for the corresponding Promise methods.

// before
await Promise.all(users.map(async u => fetchProfile(u.id))
// after
await.all users.map(async u => fetchProfile(u.id))

These proposals illustrate the ongoing transformation of JavaScript, offering developers more expressive, safer, and performant language features. For a complete list of proposals at various stages, visit the TC39 proposals tracker.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ECMAScriptlanguage featuresJavaScript proposalsTC39
Alibaba Terminal Technology
Written by

Alibaba Terminal Technology

Official public account of Alibaba Terminal

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.