What's up ? 📰

Tanstack Form

Tanstack Form v1.0.0

- react

- vue

- angular

- solid

- lit

 

📰 3 mars

TypeScript

A 10x Faster TypeScript in Go

📰 15 mars

oxlint

oxlint beta 🎉

📰 15 mars

biome

biome 2 beta

 

Plugins

Domains

Multi file analysis

...

(no-floating-promise)

📰 24 mars

Bare

Node

Deno

Bun

Bare ?

📰 7 avril

Node 24

📰 23 avril

Node 24: V8 version 13.4

// Disposables && using syntax:
function create(data: string) {
	console.log(`creating disposable object with data ${data}`);
	return {
		data: data,
		[Symbol.dispose]() {
			console.log(`disposing disposable object with data ${data}`);
		},
	}
}

function main() {
  using data1 = create("first");
  using data2 = create("second");

  console.log(`using ${data1.data} and ${data2.data}`);
}

console.log("before main");
main();
console.log("after main");

// before main
// creating disposable object with data first
// creating disposable object with data second
// using first and second
// disposing disposable object with data second
// disposing disposable object with data first
// after main

Node 24: V8 version 13.4

try {
  throw "Oops; this is not an Error object";
} catch (e) {
  if (!Error.isError(e)) {
    e = new Error(e);
  }
  console.error(e.message);
}
  • Error.isError - A new static method to check if a value is an Error object

Node 24: URLPattern

const pattern = new URLPattern("https://example.com/2022/feb/*");
console.log(pattern.test("https://example.com/2022/feb/xc44rsz")); // true
console.log(pattern.test("https://example.com/2022/Feb/xc44rsz")); // false

Node 24

AsyncLocalStorage defaults to AsyncContextFrame

URLPattern as a Global

Undici 7.0.0

Permission Model Improvements

Test Runner Enhancements

V8 v13.4

ES2025 !

  • JavaScript: marque Sun (Oracle)
  • Normalisé à l'ECMA
  • TC39 groupe en charge d'ES

📰 en juin

Le process

  • Stage 0    🎉
  • Stage 1    💡
  • Stage 2    📃
  • Stage 2.7 📑
  • Stage 3    🔥
  • Stage 4    🚀 

Promise.try()

type AsyncNegator = (val: number) => number | Promise<number>;
function subtract(a: number, b: number, negate: AsyncNegator): Promise<number> {
    return Promise.try(() => negate(b)).then(negB => a + negB);
}

ES2025

type AsyncNegator = (val: number) => number | Promise<number>;
function subtract(a: number, b: number, negate: AsyncNegator): Promise<number> {
    return Promise.resolve(negate(b)).then(negB => a + negB);
}

Duplicate Named Capture Groups


const damnedRegex = /(?<year>[0-9]{4})-[0-9]{2}|[0-9]{2}-(?<year>[0-9]{4})/
// Impossible avant ES2025 d'utiliser <year> 2 fois

ES2025

const RE_DATE = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/

const {groups: {day, month, year}} = RE_DATE.exec('1999-12-31')
const myFruits = new Set(['🍎', '🍐', '🥝'])
const yourFruits = new Set(['🥥', '🍐', '🫒'])

myFruits.intersection(yourFruits) // 🍐

myFruits.union(yourFruits) // 🍎, 🍐, 🥝, 🥥, 🫒

myFruits.difference(yourFruits) // 🍎, 🥝

myFruits.symmetricDifference(yourFruits) // 🍎, 🥝, 🥥, 🫒

myFruits.isSubsetOf(new Set(['🍎', '🍐', '🥝', '🥥'])) // true

new Set(['🍎', '🍐', '🥝', '🥥']).isSupersetOf(myFruits) // true

myFruits.isDisjointFrom(yourFruits) // false

ES2025

New Set Methods

function clearName(text, name) {
  return text.replace(new RegExp(`${name}`, "g"), "");
}

const dynamicNamePattern = ".*"

clearName("My name is Patrice and should not appear here", dynamicNamePattern)
// ""

ES2025

Regex.escape()

function clearName(text, name) {
  return text.replace(new RegExp(`${RegExp.escape(name)}`, "g"), "");
}

const dynamicNamePattern = ".*"

clearName("My name is Patrice and should not appear here", dynamicNamePattern)
// "My name is Patrice and should not appear here"

Iterator helpers .map()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const result = naturals()
  .map(value => {
    return value * value;
  });
result.next(); //  {value: 0, done: false};
result.next(); //  {value: 1, done: false};
result.next(); //  {value: 4, done: false};

ES2025

Iterator helpers .filter()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const result = naturals()
  .filter(value => {
    return value % 2 == 0;
  });
result.next(); //  {value: 0, done: false};
result.next(); //  {value: 2, done: false};
result.next(); //  {value: 4, done: false};

ES2025

Iterator helpers .take()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const result = naturals()
  .take(3);
result.next(); //  {value: 0, done: false};
result.next(); //  {value: 1, done: false};
result.next(); //  {value: 2, done: false};
result.next(); //  {value: undefined, done: true};

ES2025

Iterator helpers .flatMap()

const sunny = ["It's Sunny in", "", "California"].values();

const result = sunny
  .flatMap(value => value.split(" ").values());
result.next(); //  {value: "It's", done: false};
result.next(); //  {value: "Sunny", done: false};
result.next(); //  {value: "in", done: false};
result.next(); //  {value: "", done: false};
result.next(); //  {value: "California", done: false};
result.next(); //  {value: undefined, done: true};

ES2025

Iterator helpers .reduce()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const result = naturals()
  .take(5)
  .reduce((sum, value) => {
    return sum + value;
  }, 3);

result // 13

ES2025

Iterator helpers .toArray()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const result = naturals()
  .take(5)
  .toArray();

result // [0, 1, 2, 3, 4]

ES2025

Iterator helpers .some()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const iter = naturals().take(4);

iter.some(v => v > 1); // true
iter.some(v => true); // false, iterator is already consumed.

naturals().take(4).some(v => v > 1); // true
naturals().take(4).some(v => v == 1); // true, acting on a new iterator

ES2025

Iterator helpers .every()

function* naturals() {
  let i = 0;
  while (true) {
    yield i;
    i += 1;
  }
}

const iter = naturals().take(10);

iter.every(v => v >= 0); // true
iter.every(v => false); // true, iterator is already consumed.

naturals().take(4).every(v => v > 0); // false, first value is 0
naturals().take(4).every(v => v >= 0); // true, acting on a new iterator

ES2025

Iterator helpers Iterator.from()

class Iter {
  next() {
    return { done: false, value: 1 };
  }
}

const iter = new Iter();
const wrapper = Iterator.from(iter);

wrapper.next() // { value: 1, done: false }

ES2025

import attributes

import json from "./foo.json" with { type: "json" };

ES2025

new Worker("foo.wasm", { type: "module", with: { type: "webassembly" } });

JSON modules

import json from "./foo.json" with { type: "json" };

ES2025

Enjoy ! 🎉

Et merci :)

ES2025: https://github.com/tc39/proposals/blob/main/finished-proposals.md

tc39 process: https://tc39.es/process-document/

Node 24: https://github.com/nodejs/node/pull/57609

TS en Go: https://devblogs.microsoft.com/typescript/typescript-native-port/

oxlint: https://oxc.rs/blog/2025-03-15-oxlint-beta.html

biome2: https://biomejs.dev/blog/biome-v2-0-beta/

tanstack form: https://tanstack.com/form/latest

tanstcak vs. next: https://www.kylegill.com/essays/next-vs-tanstack

Bare: https://bare.pears.com/#why

Vrac

JS battle https://deno.com/blog/deno-v-oracle3?ck_subscriber_id=310512965
https://open.nytimes.com/how-the-new-york-times-systematically-migrated-from-enzyme-into-react-testing-library-b3ea538d001c
A FU: https://node-modules.dev/?ck_subscriber_id=310512965