What's Coming to JavaScript

5 hours ago 2

Deno is a JavaScript company, and we believe JavaScript should be simple, powerful, and fun. Deno aims to modernize JavaScript and its tooling, with native TypeScript support, and bridging the gap between server-side and browser JavaScript with web standard APIs. As such, we’re very invested in advancing the JavaScript ecosystem and participate in standards committees like TC39, because we want JavaScript to be better and more effective for everyone.

TC39’s 108th meeting recently advanced 9 proposals across 4 stages, which represent rough ideas (stage 0) to fully standardized features (stage 4).

Here’s a brief summary of each and what that might mean for the future of JavaScript.

Stage 4

Stage 3

Stage 2

Stage 1

Advanced to stage 4

Explicit Resource Management (using)

The new using declaration (and its async variant await using) adds deterministic cleanup for resources, inspired by languages like C# and Python. Objects can define [Symbol.dispose]() (or [Symbol.asyncDispose]()) that is automatically called when a using block ends. For example:

class FileHandle { constructor(name) { this.name = name; } [Symbol.dispose]() { console.log(`${this.name} closed`); } } function readFile() { { using file = new FileHandle("data.txt"); } } readFile();

This ensures cleanup (like closing files or streams) even if an exception occurs inside the block, making resource management easier and safer.

This feature is supported in Chrome 134, Firefox 134, and Deno v2.3.

In Deno you can already use the using keyword to manage resources like file handles (Deno.File), network sockets (Deno.Conn), and more. For example, here we stop a HTTP server automatically after having made a request to it:

using server = Deno.serve({ port: 8000 }, () => { return new Response("Hello, world!"); }); const response = await fetch("http://localhost:8000"); console.log(await response.text());

The Deno team is also interested in using the using keyword to simplify async context propagation through In fact, Deno’s support for async context propagation (stage 2) already enables us to do things like auto-instrumentation of console.log to include HTTP information. However, right now every time you want to create a new span to track some work, you need to create a new function and run it. This is cumbersome:

async function doWork() { const parent = tracer.startSpan("doWork"); return parent.run(async () => { console.log("doing some work..."); return true; }); }

The Deno team is proposing disposable AsyncContext.Variable, which would allow you to use the using keyword to simplify this code:

async function doWork() { using parent = tracer.startActiveSpan("doWork"); console.log("doing some work..."); return true; }

See? Much less boilerplate!

Array.fromAsync

Array.fromAsync is like Array.from but works with async iterables, returning a Promise that resolves to the resulting array. It also supports a mapping function and thisArg, just like Array.from.

For example, given an async generator of values, you can write:

async function* generate() { yield await Promise.resolve(1); yield await Promise.resolve(2); } const nums = await Array.fromAsync(generate());

Here Array.fromAsync(generate()) returns a promise that resolves to [1, 2] once all yielded values are ready. This makes common async collection patterns much simpler and more readable.

Array.fromAsync is available in all browsers, as well as Deno v1.38 and Node v22.

Error.isError

Error.isError(value) is a new built‑in for reliably detecting error objects. It returns true if value is any kind of Error (including cross-realm or subclassed errors), and false otherwise. For example:

Error.isError(new TypeError("oops")); Error.isError({ name: "TypeError", message: "oops" });

While this is almost never needed, authoring certain code, such as some polyfills, can be difficult without this functionality.

Error.isError has support in all browsers, as well as in Deno v2.2.

Stage 3

Immutable ArrayBuffer

Immutable ArrayBuffer is now at Stage 3, introducing transferToImmutable() and sliceToImmutable() methods. Calling transferToImmutable() on a buffer moves its data into a new, unchangeable buffer and detaches the original. For example:

let buf = new ArrayBuffer(100); let imm = buf.transferToImmutable(); console.log(buf.byteLength, imm.byteLength); imm[0] = 1;

Similarly, sliceToImmutable(start, end) creates an immutable copy of a subrange. Immutable buffers cannot be detached or modified, which makes sharing binary data (e.g. across threads or workers) safer and more efficient.

We are planning to make use of this in Deno to optimize various APIs that take byte arrays as inputs, such as new Response() or Deno.writeFile(). This will allow us to avoid unnecessary copies and improve performance when working with binary data.

Stage 2

Random.Seeded

Current pseudo-random number generator methods (Math.random() for instance) are automatically seeded, making it not reproducible across runs or realms. However, there are times when you’d want a reproducible set of random values.

This proposal for a new SeededPRNG class provides reproducible randomness by allowing you to set a seed. You create a Random.Seeded(seedValue) object and use its .random() method instead of Math.random(). For example:

const prng = new Random.Seeded(42); for (let i = 0; i < 3; i++) { console.log(prng.random()); }

This is useful in games or simulations where repeatability matters. You can also derive new seeds or clone state from an existing PRNG for complex scenarios.

Number.prototype.clamp

The Number.prototype.clamp(min, max) function (originally Math.clamp) returns a number bounded between min and max. This is handy for keeping values within a range. For example:

(5).clamp(0, 10); (-5).clamp(0, 10); (15).clamp(0, 10);

If min > max, it throws a RangeError. This avoids verbose patterns like Math.min(Math.max(x, min), max) and clarifies intent.

Stage 1

Keep Trailing Zeros

New formatting options in Intl.NumberFormat will allow preserving or stripping trailing zeros in formatted numbers, which is useful for representing human-readable decimal values (e.g. money).

The trailingZeroDisplay: "auto" setting (default) keeps zeros according to the specified precision; "stripIfInteger" removes them when the number is an integer. For example:

new Intl.NumberFormat("en", { minimumFractionDigits: 2, trailingZeroDisplay: "auto", }) .format(1.5); new Intl.NumberFormat("en", { minimumFractionDigits: 0, trailingZeroDisplay: "stripIfInteger", }) .format(2);

This gives developers finer control over number formatting (e.g. currency or fixed-point output) without ad-hoc string manipulation.

Comparisons

The Comparisons proposal aims to standardize how JavaScript produces human-readable representations of values — similar to util.inspect in Node.js or how test runners print diffs.

The goal is to give test frameworks and console tools a consistent way to generate diffs — especially across runtimes and realms.

Random Functions

This proposal introduces a new Random namespace with convenience methods to avoid common pitfalls with randomness. The methods in the Random namespace not only can generate random numerical values, but also accept and return collections.

Here are some examples:

Random.int(-5, 5); Random.number(0, 10); Random.number(0, 5, 0.1); const name = Random.take(["Alice", "Bob", "Carol"], 2); Random.take(["Alice", "Bob", "Carol"], 2, { replace: true }); Random.take(["Alice", "Bob", "Carol"], 2, { weights: [1, 1, 5] }); Random.sample(["Alice", "Bob", "Carol"]); Random.shuffle([1, 2, 3, 4]); const shuffled = Random.toShuffled([1, 2, 3, 4]);

The goal is to make random-related code safer and more concise, reducing off-by-one errors and improving consistency.

TC39 continues to evolve and improve JavaScript to meet the needs of modern developers. Deno is committed to web standards and actively participates in these discussions to use JavaScript, which directly simplifies how you could write JavaScript in Deno (see async context propagation and our built-in OpenTelemetry API). The next TC39 meeting where these proposals will be further discussed is scheduled for late September.

🚨️ There have been major updates to Deno Deploy! 🚨️

and much more!

Get early access today.

Read Entire Article