ECMAScript 2025 (ES16) is the year's batch of practical improvements to JavaScript. TC39 ratified the spec in June 2025. Here are the parts worth knowing about.
New Set Methods
Set finally gets the set-theory methods that should have been there from the start. Union, intersection, difference, and the rest. No more writing them by hand.
const frontend = new Set(['React', 'Vue', 'Svelte', 'Angular']);
const popular = new Set(['React', 'Vue', 'Node.js', 'Express']);
// Intersection — common elements
frontend.intersection(popular);
// Set {'React', 'Vue'}
// Union
frontend.union(popular);
// Set {'React', 'Vue', 'Svelte', 'Angular', 'Node.js', 'Express'}
// Difference — in frontend, not in popular
frontend.difference(popular);
// Set {'Svelte', 'Angular'}
// Symmetric difference
frontend.symmetricDifference(popular);
// Set {'Svelte', 'Angular', 'Node.js', 'Express'}
// Checks
frontend.isSubsetOf(popular); // false
frontend.isSupersetOf(popular); // false
frontend.isDisjointFrom(popular); // falseAll of these return a new Set instead of mutating. Reads cleaner, behaves predictably.
Import Attributes and JSON Modules
Import Attributes (the renamed Import Assertions) let you declare the type of an imported module. The headline use case is JSON imports.
// Import JSON with a type attribute
import config from './config.json' with { type: 'json' };
console.log(config.version); // "1.0.0"
// Dynamic import also supports attributes
const data = await import('./data.json', {
with: { type: 'json' }
});The with keyword replaces the older assert syntax. Browsers and Node.js already ship the new one.with keyword replaces the previous assert syntax. Browsers and Node.js already support the new variant.
Promise.try
A static method that wraps any function, sync or async, into a Promise. Useful when you want one error-handling path for both.
// Before: manual wrapping needed
function fetchData(id) {
// If validate() throws synchronously,
// .catch() won't intercept it
return Promise.resolve().then(() => {
validate(id);
return fetch(`/api/data/${id}`);
});
}
// Now: Promise.try handles both cases
function fetchData(id) {
return Promise.try(() => {
validate(id); // sync error — caught
return fetch(`/api/data/${id}`); // async — works too
});
}RegExp.escape
A simple method that's been missing for years: escape special characters in a string so it's safe to use in a regex.
const userInput = 'price: $100 (USD)';
const escaped = RegExp.escape(userInput);
// 'price\:\ \$100\ \(USD\)'
const regex = new RegExp(escaped);
regex.test('price: $100 (USD)'); // trueNo more shipping a tiny escape utility from npm. It's in the language now.
Iterator Helpers
Iterators finally get the array-style methods: map, filter, take, drop, and friends. They run lazily, so you don't build intermediate arrays along the way.
function* naturals() {
let n = 1;
while (true) yield n++;
}
// First 5 even numbers — lazily, no arrays
const result = naturals()
.filter(n => n % 2 === 0)
.take(5)
.toArray();
console.log(result); // [2, 4, 6, 8, 10]
// Map + forEach on a Map iterator
const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
map.values()
.map(v => v * 10)
.forEach(v => console.log(v)); // 10, 20, 30Useful when you're walking a large or infinite sequence and building an array would be wasteful.
Browser and Node.js Support
Most of these features are already in Chrome 126+, Firefox 127+, Safari 18+, and Node.js 22+. Set methods and Iterator Helpers have the widest reach. Import Attributes with JSON modules work in Node.js and most bundlers. Promise.try and RegExp.escape are landing in the latest engine releases.
Conclusion
ECMAScript 2025 is a quiet but useful release. Set methods, Iterator Helpers, Promise.try, and RegExp.escape each close a gap that's been bothering people for a while. All available in modern engines. Worth using.
