What New TC39 Proposals Are Shaping JavaScript’s Future?
Recent TC39 Stage‑1 proposals introduce iterator deduplication, enhanced template literals, function and object literal decorators, concurrency controls for async iterators, unordered async helpers, immutable ArrayBuffers, a measurement API, Array.zip utilities, reactive Signals, and stricter resource‑management using enforcement, each aiming to extend JavaScript’s core capabilities.
When a proposal reaches Stage 1, its value and design are officially accepted by TC39 and the standardisation process begins.
Iterator Unique
Proposal address: proposal-iterator-unique.
Deduplicating items in a collection is common, but for JavaScript iterators it adds complexity. A simple Set‑based approach works but has drawbacks such as consuming the entire iterator, not supporting infinite iterators, mishandling -0, and failing on non‑iterable iterators.
<code>let uniques = new Set(iter).values();</code>The proposal adds
Iterator.prototype.uniqBywith an optional mapping function to perform deduplication.
<code>let uniques = iter.uniqBy();
let uniques = iter.uniqBy(obj => obj.field);</code>Improved Escapes for Template Literals
Proposal address: proposal-improve-template-literals.
Current template strings require manual escaping of special characters using
String.rawor
String.dedent, yet characters like backticks or
${are not handled correctly.
<code>let query = `
select *
from \`users\`
where \`name\` = ?
`;</code>The proposal introduces a new template literal syntax that eliminates the need for manual escaping.
<code>// syntax TBD, just use @sken130's strawperson draft as demo
let query = @``
select *
from \`users\`
where \`name\` = ?
``</code>Function and Object Literal Element Decorators
Proposal address: proposal-function-and-object-literal-element-decorators.
The proposal enables decorator syntax on function expressions, function declarations, and object literals.
<code>// logging/tracing
@logged
function doWork() { ... }
// utility wrappers
const onpress = @debounce(250) (e) => console.log("button pressed: ", e.pressed);
// metadata
@ParamTypes(() => [Number, Number])
@ReturnType(() => Number)
function add(x, y) { return x + y; }
// React Functional Components
@withStyles({
root: { border: '1px solid black' },
})
@React.forwardRef
function Button(props, forwardedRef) { ... }
const addOne = (_target, _context) => x => x + 1;
const obj = { @addOne x: 2 };
console.log(obj.x); // 3</code>Concurrency Control
Proposal address: proposal-concurrency-control.
Extends async‑iterator‑helpers with a
limitparameter and a flexible
CountingGovernorto provide simple concurrency control.
Unordered Async Iterator Helpers
Proposal address: proposal-unordered-async-iterator-helpers.
Unlike ordered async‑iterator helpers such as
forEachor
some, unordered helpers relax ordering constraints, potentially improving performance and throughput.
Immutable ArrayBuffers
Proposal address: https://github.com/tc39/proposal-immutable-arraybuffer.
Current
ArrayBuffercan be resized or transferred; this proposal adds immutable buffers via
transferToImmutable()and a read‑only
immutableproperty.
transferToImmutable(): moves the current buffer’s contents to a new immutable buffer, detaching the original.
immutable: read‑only flag indicating immutability.
Immutable buffers cannot be detached, resized, or transferred, and their maximum byte length equals the current length. TypedArray and DataView views over an immutable buffer can be frozen.
<code>const consumeIntoNetstring = data => {
// Transfer to a new ArrayBuffer with room for the netstring framing.
const prefix = new TextEncoder().encode(`${data.length}:`);
const buf = data.buffer.transfer(prefix.length + data.length + 1);
// Frame the data.
const tmpArr = new Uint8Array(buf);
tmpArr.copyWithin(prefix.length, 0);
tmpArr.set(prefix);
tmpArr[tmpArr.length - 1] = 0x2C;
// Transfer to an immutable ArrayBuffer backing a frozen Uint8Array.
const frozenNetstring = Object.freeze(new Uint8Array(buf.transferToImmutable()));
assert(buf.detached);
return frozenNetstring;
};
const input = new TextEncoder().encode('hello world!');
const result = consumeIntoNetstring(input);
assert(Object.isFrozen(result));
try { result[0] = 0; } catch (_) {}
try { new Uint8Array(result.buffer)[0] = 1; } catch (_) {}
try { result.buffer.transferToImmutable(); } catch (_) {}
assert(String.fromCharCode(...result) === '12:hello world!,');</code>Measure
Proposal address: https://github.com/ben-allen/proposal-measure.
Introduces a
Measureobject to represent values with units and convert between them.
unit: unit string.
value: primary unit numeric value.
minorValue: secondary unit value, if any.
Prototype methods:
convert(unit, precision): converts to the given unit.
localeConvert(locale, usage): converts based on locale data from CLDR’s
units.xml.
<code>let m = new Measure(1.8, "meter");
m.convert('foot', 2); // { value: 5.91, unit: "foot" }
m.localeConvert("en-CA", "personHeight"); // { value: 5, minorValue: 11 }
let m2 = new Measure(4000, "foot");
m2.convert("kilometer"); // { value: 1.2192, unit: "kilometer" }
m2.localeConvert('en-US', "road"); // { value: 0.76, unit: "mile" }</code>Array.zip
Proposal address: proposal-array-zip.
Adds static methods
Array.zipand
Array.zipKeyedto synchronize iteration over multiple arrays, based on the joint‑iteration proposal.
Signals
Proposal address: proposal-signals.
Signals provide a reactive programming model that automatically tracks dependencies, lazily evaluates, and memoizes results, aiming to simplify state‑update management across frameworks.
<code>const counter = new Signal.State(0);
const isEven = new Signal.Computed(() => (counter.get() & 1) == 0);
const parity = new Signal.Computed(() => isEven.get() ? "even" : "odd");
declare function effect(cb: () => void): () => void;
effect(() => element.innerText = parity.get());
setInterval(() => counter.set(counter.get() + 1), 1000);
</code>The proposal was discussed in April 2024 and remains in early stages.
Strict using
Proposal address: proposal-using-enforcement.
Builds on explicit‑resource‑management, enforcing that resources implementing
Symbol.entermust be used with a
usingstatement, ensuring proper cleanup.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.