Skip to content

Commit 8ef0d2a

Browse files
[BUGFIX beta] Align EmberArray.reduce with native semantics.
1 parent 0802488 commit 8ef0d2a

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

packages/@ember/-internals/runtime/tests/array/reduce-test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ class ReduceTests extends AbstractTestCase {
88
this.assert.equal(res, 6);
99
}
1010

11+
'@test uses the first item as the initial accumulator when not provided'() {
12+
let obj = this.newObject([1, 2, 3]);
13+
let res = obj.reduce((previousValue, item) => previousValue + item);
14+
this.assert.equal(res, 6);
15+
}
16+
1117
'@test passes index of item to callback'() {
1218
let obj = this.newObject([1, 2, 3]);
1319
let res = obj.reduce((previousValue, item, index) => previousValue + index, 0);
@@ -19,6 +25,15 @@ class ReduceTests extends AbstractTestCase {
1925
let res = obj.reduce((previousValue, item, index, enumerable) => enumerable, 0);
2026
this.assert.equal(res, obj);
2127
}
28+
29+
'@test throws when called on an empty array without an initial value'() {
30+
let obj = this.newObject([]);
31+
32+
this.assert.throws(
33+
() => obj.reduce(() => 0),
34+
/Reduce of empty array with no initial value/
35+
);
36+
}
2237
}
2338

2439
runArrayTests('reduce', ReduceTests);

packages/@ember/array/index.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,19 +1380,32 @@ const EmberArray = Mixin.create(Enumerable, {
13801380
return any(this, callback);
13811381
},
13821382

1383-
// FIXME: When called without initialValue, behavior does not match native behavior
13841383
reduce<T, V>(
13851384
this: EmberArray<T>,
13861385
callback: (summation: V, current: T, index: number, arr: EmberArray<T>) => V,
1387-
initialValue: V
1386+
initialValue?: V
13881387
) {
13891388
assert('`reduce` expects a function as first argument.', typeof callback === 'function');
13901389

1391-
let ret = initialValue;
1390+
let length = this.length;
1391+
let startIndex = 0;
1392+
let ret: V;
1393+
1394+
if (arguments.length > 1) {
1395+
ret = initialValue as V;
1396+
} else {
1397+
if (length === 0) {
1398+
throw new TypeError('Reduce of empty array with no initial value');
1399+
}
1400+
1401+
ret = objectAt(this, 0) as unknown as V;
1402+
startIndex = 1;
1403+
}
13921404

1393-
this.forEach(function (item, i) {
1394-
ret = callback(ret, item, i, this);
1395-
}, this);
1405+
for (let index = startIndex; index < length; index++) {
1406+
let item = objectAt(this, index) as T;
1407+
ret = callback(ret, item, index, this);
1408+
}
13961409

13971410
return ret;
13981411
},

0 commit comments

Comments
 (0)