Skip to content

Commit da8c0cf

Browse files
committed
lib: add Math.sumPrecise type definition (ES2026 / esnext)
Math.sumPrecise is part of the TC39 proposal-math-sum which reached Stage 4 on 2025-07-28, making it part of ES2026. Already implemented in Firefox 137+, Safari 18.4, and Bun, but not yet in V8/Node.js. Adds src/lib/esnext.math.d.ts with the Math interface extension, and wires it into esnext.d.ts and libs.json. Fixes #63427
1 parent 55423ab commit da8c0cf

7 files changed

Lines changed: 288 additions & 3 deletions

File tree

src/compiler/commandLineParser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ const libEntries: [string, string][] = [
249249
["esnext.iterator", "lib.es2025.iterator.d.ts"],
250250
["esnext.promise", "lib.es2025.promise.d.ts"],
251251
// ESNext By-feature options
252-
["esnext.array", "lib.esnext.array.d.ts"],
252+
["esnext.array", "lib.esnext.array.d.ts"],
253+
["esnext.math", "lib.esnext.math.d.ts"],
253254
["esnext.collection", "lib.esnext.collection.d.ts"],
254255
["esnext.date", "lib.esnext.date.d.ts"],
255256
["esnext.decorators", "lib.esnext.decorators.d.ts"],

src/lib/esnext.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
/// <reference lib="esnext.typedarrays" />
1010
/// <reference lib="esnext.temporal" />
1111
/// <reference lib="esnext.date" />
12+
/// <reference lib="esnext.math" />

src/lib/esnext.math.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/// <reference lib="es2015.iterable" />
2+
3+
interface Math {
4+
/**
5+
* Returns the sum of the values in the iterable using a more precise
6+
* summation algorithm than naive floating-point addition.
7+
* Returns `-0` if the iterable is empty.
8+
* @param numbers An iterable (such as an Array) of numbers.
9+
* @throws {TypeError} If `numbers` is not iterable, or if any value in the iterable is not of type `number`.
10+
* @throws {RangeError} If the iterable yields 2^53 or more values.
11+
* @see https://tc39.es/proposal-math-sum/
12+
*/
13+
sumPrecise(numbers: Iterable<number>): number;
14+
}

src/lib/libs.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,11 @@
8383
"es2025.collection",
8484
"es2025.float16",
8585
"es2025.intl",
86-
"es2025.iterator",
86+
"es2025.iterator",
8787
"es2025.promise",
8888
"es2025.regexp",
89-
"esnext.array",
89+
"esnext.array",
90+
"esnext.math",
9091
"esnext.collection",
9192
"esnext.date",
9293
"esnext.decorators",
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//// [tests/cases/conformance/esnext/mathSumPrecise.ts] ////
2+
3+
=== mathSumPrecise.ts ===
4+
// Basic usage with array
5+
const sum1 = Math.sumPrecise([1, 2, 3]);
6+
>sum1 : Symbol(sum1, Decl(mathSumPrecise.ts, 1, 5))
7+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
8+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
9+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
10+
11+
// Floating point precision
12+
const sum2 = Math.sumPrecise([1e20, 0.1, -1e20]);
13+
>sum2 : Symbol(sum2, Decl(mathSumPrecise.ts, 4, 5))
14+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
15+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
16+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
17+
18+
// Empty iterable returns -0
19+
const sum3 = Math.sumPrecise([]);
20+
>sum3 : Symbol(sum3, Decl(mathSumPrecise.ts, 7, 5))
21+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
22+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
23+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
24+
25+
// Works with any Iterable<number>
26+
const sum4 = Math.sumPrecise(new Set([1, 2, 3]));
27+
>sum4 : Symbol(sum4, Decl(mathSumPrecise.ts, 10, 5))
28+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
29+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
30+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
31+
>Set : Symbol(Set, Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.collection.d.ts, --, --))
32+
33+
function* gen(): Iterable<number> {
34+
>gen : Symbol(gen, Decl(mathSumPrecise.ts, 10, 49))
35+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
36+
37+
yield 0.1;
38+
yield 0.2;
39+
}
40+
const sum5 = Math.sumPrecise(gen());
41+
>sum5 : Symbol(sum5, Decl(mathSumPrecise.ts, 16, 5))
42+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
43+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
44+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
45+
>gen : Symbol(gen, Decl(mathSumPrecise.ts, 10, 49))
46+
47+
// Return type is number
48+
const result: number = Math.sumPrecise([1, 2, 3]);
49+
>result : Symbol(result, Decl(mathSumPrecise.ts, 19, 5))
50+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
51+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
52+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
53+
54+
// @ts-expect-error - BigInt is not a number
55+
Math.sumPrecise([1n, 2n]);
56+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
57+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
58+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
59+
60+
// @ts-expect-error - string is not a number
61+
Math.sumPrecise(["a", "b"]);
62+
>Math.sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
63+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2025.float16.d.ts, --, --) ... and 1 more)
64+
>sumPrecise : Symbol(Math.sumPrecise, Decl(lib.esnext.math.d.ts, --, --))
65+
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//// [tests/cases/conformance/esnext/mathSumPrecise.ts] ////
2+
3+
=== mathSumPrecise.ts ===
4+
// Basic usage with array
5+
const sum1 = Math.sumPrecise([1, 2, 3]);
6+
>sum1 : number
7+
> : ^^^^^^
8+
>Math.sumPrecise([1, 2, 3]) : number
9+
> : ^^^^^^
10+
>Math.sumPrecise : (numbers: Iterable<number>) => number
11+
> : ^ ^^ ^^^^^
12+
>Math : Math
13+
> : ^^^^
14+
>sumPrecise : (numbers: Iterable<number>) => number
15+
> : ^ ^^ ^^^^^
16+
>[1, 2, 3] : number[]
17+
> : ^^^^^^^^
18+
>1 : 1
19+
> : ^
20+
>2 : 2
21+
> : ^
22+
>3 : 3
23+
> : ^
24+
25+
// Floating point precision
26+
const sum2 = Math.sumPrecise([1e20, 0.1, -1e20]);
27+
>sum2 : number
28+
> : ^^^^^^
29+
>Math.sumPrecise([1e20, 0.1, -1e20]) : number
30+
> : ^^^^^^
31+
>Math.sumPrecise : (numbers: Iterable<number>) => number
32+
> : ^ ^^ ^^^^^
33+
>Math : Math
34+
> : ^^^^
35+
>sumPrecise : (numbers: Iterable<number>) => number
36+
> : ^ ^^ ^^^^^
37+
>[1e20, 0.1, -1e20] : number[]
38+
> : ^^^^^^^^
39+
>1e20 : 100000000000000000000
40+
> : ^^^^^^^^^^^^^^^^^^^^^
41+
>0.1 : 0.1
42+
> : ^^^
43+
>-1e20 : -100000000000000000000
44+
> : ^^^^^^^^^^^^^^^^^^^^^^
45+
>1e20 : 100000000000000000000
46+
> : ^^^^^^^^^^^^^^^^^^^^^
47+
48+
// Empty iterable returns -0
49+
const sum3 = Math.sumPrecise([]);
50+
>sum3 : number
51+
> : ^^^^^^
52+
>Math.sumPrecise([]) : number
53+
> : ^^^^^^
54+
>Math.sumPrecise : (numbers: Iterable<number>) => number
55+
> : ^ ^^ ^^^^^
56+
>Math : Math
57+
> : ^^^^
58+
>sumPrecise : (numbers: Iterable<number>) => number
59+
> : ^ ^^ ^^^^^
60+
>[] : never[]
61+
> : ^^^^^^^
62+
63+
// Works with any Iterable<number>
64+
const sum4 = Math.sumPrecise(new Set([1, 2, 3]));
65+
>sum4 : number
66+
> : ^^^^^^
67+
>Math.sumPrecise(new Set([1, 2, 3])) : number
68+
> : ^^^^^^
69+
>Math.sumPrecise : (numbers: Iterable<number>) => number
70+
> : ^ ^^ ^^^^^
71+
>Math : Math
72+
> : ^^^^
73+
>sumPrecise : (numbers: Iterable<number>) => number
74+
> : ^ ^^ ^^^^^
75+
>new Set([1, 2, 3]) : Set<number>
76+
> : ^^^^^^^^^^^
77+
>Set : SetConstructor
78+
> : ^^^^^^^^^^^^^^
79+
>[1, 2, 3] : number[]
80+
> : ^^^^^^^^
81+
>1 : 1
82+
> : ^
83+
>2 : 2
84+
> : ^
85+
>3 : 3
86+
> : ^
87+
88+
function* gen(): Iterable<number> {
89+
>gen : () => Iterable<number>
90+
> : ^^^^^^
91+
92+
yield 0.1;
93+
>yield 0.1 : any
94+
>0.1 : 0.1
95+
> : ^^^
96+
97+
yield 0.2;
98+
>yield 0.2 : any
99+
>0.2 : 0.2
100+
> : ^^^
101+
}
102+
const sum5 = Math.sumPrecise(gen());
103+
>sum5 : number
104+
> : ^^^^^^
105+
>Math.sumPrecise(gen()) : number
106+
> : ^^^^^^
107+
>Math.sumPrecise : (numbers: Iterable<number>) => number
108+
> : ^ ^^ ^^^^^
109+
>Math : Math
110+
> : ^^^^
111+
>sumPrecise : (numbers: Iterable<number>) => number
112+
> : ^ ^^ ^^^^^
113+
>gen() : Iterable<number>
114+
> : ^^^^^^^^^^^^^^^^
115+
>gen : () => Iterable<number>
116+
> : ^^^^^^
117+
118+
// Return type is number
119+
const result: number = Math.sumPrecise([1, 2, 3]);
120+
>result : number
121+
> : ^^^^^^
122+
>Math.sumPrecise([1, 2, 3]) : number
123+
> : ^^^^^^
124+
>Math.sumPrecise : (numbers: Iterable<number>) => number
125+
> : ^ ^^ ^^^^^
126+
>Math : Math
127+
> : ^^^^
128+
>sumPrecise : (numbers: Iterable<number>) => number
129+
> : ^ ^^ ^^^^^
130+
>[1, 2, 3] : number[]
131+
> : ^^^^^^^^
132+
>1 : 1
133+
> : ^
134+
>2 : 2
135+
> : ^
136+
>3 : 3
137+
> : ^
138+
139+
// @ts-expect-error - BigInt is not a number
140+
Math.sumPrecise([1n, 2n]);
141+
>Math.sumPrecise([1n, 2n]) : number
142+
> : ^^^^^^
143+
>Math.sumPrecise : (numbers: Iterable<number>) => number
144+
> : ^ ^^ ^^^^^
145+
>Math : Math
146+
> : ^^^^
147+
>sumPrecise : (numbers: Iterable<number>) => number
148+
> : ^ ^^ ^^^^^
149+
>[1n, 2n] : bigint[]
150+
> : ^^^^^^^^
151+
>1n : 1n
152+
> : ^^
153+
>2n : 2n
154+
> : ^^
155+
156+
// @ts-expect-error - string is not a number
157+
Math.sumPrecise(["a", "b"]);
158+
>Math.sumPrecise(["a", "b"]) : number
159+
> : ^^^^^^
160+
>Math.sumPrecise : (numbers: Iterable<number>) => number
161+
> : ^ ^^ ^^^^^
162+
>Math : Math
163+
> : ^^^^
164+
>sumPrecise : (numbers: Iterable<number>) => number
165+
> : ^ ^^ ^^^^^
166+
>["a", "b"] : string[]
167+
> : ^^^^^^^^
168+
>"a" : "a"
169+
> : ^^^
170+
>"b" : "b"
171+
> : ^^^
172+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @target: esnext
2+
// @lib: esnext
3+
// @noemit: true
4+
// @strict: true
5+
6+
// Basic usage with array
7+
const sum1 = Math.sumPrecise([1, 2, 3]);
8+
9+
// Floating point precision
10+
const sum2 = Math.sumPrecise([1e20, 0.1, -1e20]);
11+
12+
// Empty iterable returns -0
13+
const sum3 = Math.sumPrecise([]);
14+
15+
// Works with any Iterable<number>
16+
const sum4 = Math.sumPrecise(new Set([1, 2, 3]));
17+
18+
function* gen(): Iterable<number> {
19+
yield 0.1;
20+
yield 0.2;
21+
}
22+
const sum5 = Math.sumPrecise(gen());
23+
24+
// Return type is number
25+
const result: number = Math.sumPrecise([1, 2, 3]);
26+
27+
// @ts-expect-error - BigInt is not a number
28+
Math.sumPrecise([1n, 2n]);
29+
30+
// @ts-expect-error - string is not a number
31+
Math.sumPrecise(["a", "b"]);

0 commit comments

Comments
 (0)