I would have come up with something like this: Object.entries(Array.from(new URLSearchParams("foo=1&foo=2&foo=3&blah=a&blah=b").entries()).reduce((a,[k,v]) => ({ ...a, [k]: [...a[k] ?? [], v] }), {})).map(([key, values]) => `${key}=${values.join(",")}`).join("&");
Note that this unfortunately common pattern is quadratic, which is usually not a good idea, and can have conflicts between entries and properties of Object.prototype. A similar implementation without those problems:
.reduce((a, [k, v]) => a.has(k) ? a.set(k, [v]) : (a.get(k).push(v), a), new Map())
And an alternate implementation: const input = new URLSearchParams("foo=1&foo=2&foo=3&blah=a&blah=b");
const result = new URLSearchParams();
for (const key of input.keys()) {
if (!result.has(key)) {
result.set(key, input.getAll(key).join(","));
}
}
return String(result);