What's coming to JavaScript
Deno is a JavaScript company, and we believe JavaScript should be simple,powerful, and fun. Deno aims to modernize JavaScript and its tooling, withnative TypeScript support,and bridging the gap between server-side and browser JavaScript withweb standard APIs.As such, we’re very invested in advancing the JavaScript ecosystem andparticipate in standards committees like TC39, becausewe want JavaScript to be better and more effective for everyone.
TC39’s 108th meeting recentlyadvanced 9 proposals across 4 stages, whichrepresent 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 ofJavaScript.
Advanced to stage 4
Explicit Resource Management (using)
The newusing declaration (and its async variantawait using) addsdeterministic cleanup for resources, inspired by languages like C# and Python.Objects can define[Symbol.dispose]() (or[Symbol.asyncDispose]()) that isautomatically called when ausing block ends. For example:
classFileHandle{constructor(name){this.name= name;/* open file... */}[Symbol.dispose](){console.log(`${this.name} closed`);/* close file */}}functionreadFile(){{ using file=newFileHandle("data.txt");// read from file...}// file.[Symbol.dispose]() was called here automatically}readFile();// logs "data.txt closed"
This ensures cleanup (like closing files or streams) even if an exception occursinside the block, making resource management easier and safer.
This feature is supported inChrome 134, Firefox 134,andDeno v2.3.
In Deno you can already use theusing keyword to manage resources like filehandles (Deno.File), network sockets(Deno.Conn), and more. Forexample, here we stop a HTTP server automatically after having made a request toit:
using server=Deno.serve({ port:8000},()=>{returnnewResponse("Hello, world!");});const response=awaitfetch("http://localhost:8000");console.log(await response.text());// "Hello, world!"// The server is automatically closed here because of the `using` keyword
The Deno team is also interested in using theusing keyword to simplify asynccontext propagation through In fact, Deno’s support forasync context propagation(stage 2) already enables us to do things likeauto-instrumentation ofconsole.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:
asyncfunctiondoWork(){const parent= tracer.startSpan("doWork");return parent.run(async()=>{console.log("doing some work...");returntrue;});}
The Deno team is proposingdisposableAsyncContext.Variable,which would allow you to use theusing keyword to simplify this code:
asyncfunctiondoWork(){ using parent= tracer.startActiveSpan("doWork");console.log("doing some work...");returntrue;}
See? Much less boilerplate!
Array.fromAsync
Array.fromAsync is likeArray.from but works with async iterables, returning aPromise thatresolves to the resulting array. It also supports a mapping function andthisArg, just likeArray.from.
For example, given an async generator of values, you can write:
asyncfunction*generate(){yieldawaitPromise.resolve(1);yieldawaitPromise.resolve(2);}const nums=awaitArray.fromAsync(generate());// [1, 2]
HereArray.fromAsync(generate()) returns a promise that resolves to[1, 2]once all yielded values are ready. This makes common async collection patternsmuch 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 newbuilt‑in for reliably detecting error objects. It returnstrue ifvalue isany kind of Error (including cross-realm or subclassed errors), andfalseotherwise. For example:
Error.isError(newTypeError("oops"));// trueError.isError({name:"TypeError",message:"oops"});// false
While this is almost never needed, authoring certain code, such as somepolyfills, can be difficult without this functionality.
Error.isError has support in all browsers,as well as inDeno v2.2.
Stage 3
ImmutableArrayBuffer
ImmutableArrayBuffer is now at Stage 3,introducingtransferToImmutable() andsliceToImmutable() methods. CallingtransferToImmutable() on a buffer moves its data into a new, unchangeablebuffer and detaches the original. For example:
let buf=newArrayBuffer(100);let imm= buf.transferToImmutable();// buf is now detached (byteLength 0), and imm is a new immutable ArrayBuffer of length 100console.log(buf.byteLength, imm.byteLength);// 0, 100// attempting to modify imm will throw a TypeErrorimm[0]=1;// TypeError: Cannot modify an immutable ArrayBuffer
Similarly,sliceToImmutable(start, end) creates an immutable copy of asubrange. Immutable bufferscannot be detached or modified, which makessharing 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 takebyte arrays as inputs, such asnew Response() orDeno.writeFile(). This willallow us to avoid unnecessary copies and improve performance when working withbinary 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 newSeededPRNG class provides reproducible randomness by allowing you to set aseed. You create aRandom.Seeded(seedValue) object and use its.random()method instead ofMath.random(). For example:
const prng=newRandom.Seeded(42);for(let i=0; i<3; i++){console.log(prng.random());// prints the same sequence on every run given seed 42}
This is useful in games or simulations where repeatability matters. You can alsoderive new seeds or clone state from an existingPRNG for complex scenarios.
Number.prototype.clamp
TheNumber.prototype.clamp(min, max) function(originallyMath.clamp) returns a number bounded betweenmin andmax. Thisis handy for keeping values within a range. For example:
(5).clamp(0,10);// 5(-5).clamp(0,10);// 0 (floored at 0)(15).clamp(0,10);// 10 (capped at 10)
Ifmin > max, it throws aRangeError. This avoids verbose patterns likeMath.min(Math.max(x, min), max) and clarifies intent.
Stage 1
Keep Trailing Zeros
New formatting options inIntl.NumberFormatwill allow preserving or stripping trailing zeros in formatted numbers, which isuseful for representing human-readable decimal values (e.g. money).
ThetrailingZeroDisplay: "auto" setting (default)keeps zeros according tothe specified precision;"stripIfInteger" removes them when the number is aninteger. For example:
// Keep two decimal places (auto-preserve zeros):newIntl.NumberFormat("en",{minimumFractionDigits:2,trailingZeroDisplay:"auto",}).format(1.5);// "1.50"// Strip zeros if unnecessary:newIntl.NumberFormat("en",{minimumFractionDigits:0,trailingZeroDisplay:"stripIfInteger",}).format(2);// "2" (not "2.0")
This gives developers finer control over number formatting (e.g. currency orfixed-point output) without ad-hoc string manipulation.
Comparisons
TheComparisons proposal aimsto standardize how JavaScript produceshuman-readable representations ofvalues — similar toutil.inspect in Node.js or how test runners print diffs.
The goal is to give test frameworks and console tools a consistent way togenerate diffs — especially across runtimes and realms.
Random Functions
This proposal introduces a newRandom namespacewith convenience methods to avoid common pitfalls with randomness. The methodsin theRandom namespace not only can generate random numerical values, butalso accept and return collections.
Here are some examples:
// Random integer between -5 and 5Random.int(-5,5);// -1// Random Number between 0 and 10Random.number(0,10);// 8// Random number between 0, 5 with steps of 0.1Random.number(0,5,0.1);// 1.1// Randomly select n items from an array.const name=Random.take(["Alice","Bob","Carol"],2);// ['Alice', 'Bob']// With replacement.Random.take(["Alice","Bob","Carol"],2,{replace:true});// ['Alice', 'Alice']// With weights.Random.take(["Alice","Bob","Carol"],2,{weights:[1,1,5]});// ['Alice', 'Bob']// Select one random item.Random.sample(["Alice","Bob","Carol"]);// 'Bob'// Mutate and return a "shuffled" Array in-place.Random.shuffle([1,2,3,4]);// [4,2,1,3]// Return a new shuffled array.const shuffled=Random.toShuffled([1,2,3,4]);
The goal is to make random-related codesafer and more concise, reducingoff-by-one errors and improving consistency.
What’s next
TC39 continues to evolve and improve JavaScript to meet the needs of moderndevelopers. Deno is committed to web standards and actively participates inthese discussions to use JavaScript, which directly simplifies how you couldwrite JavaScript in Deno (seeasync context propagation andourbuilt-in OpenTelemetry API).The next TC39 meeting where these proposals will be further discussed isscheduled for late September.
🚨️There have been major updates to Deno Deploy! 🚨️
- Improved Playgrounds with livestreaming logs, traces, and templates like Next.js
- Automatic and immediate observability and telemetry
- Simpler management for environment variables
andmuch more!

