question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Reduce without an initialValue should be illegal on a potentially empty array

See original GitHub issue

TypeScript Version: 3.8.0-dev.20191025

Search Terms: reduce no initialvalue

Code

[].reduce((a,b) => a+b /*, initialvalue NOT specified*/);

Expected behavior: Should not compile

Actual behavior: Compiles and crashes:

~ $ tsc reduce.ts; echo $?
0
~ $ js reduce.js
reduce.js:1: TypeError: reduce of empty array with no initial value

Related Issues: None relevant, https://github.com/microsoft/TypeScript/issues/28901 is trying to make TS accept something that it doesn’t accept currently; I’m asking the opposite: that something which is accepted became not accepted.

Some ideas: Retiring reduce with no initialValue from the type Array as this is unsafe to keep around; people should provide an initialValue if their array can be empty:

--- a/typescript/lib/lib.es5.d.ts	2019-10-25 12:33:06.312693040 +0200
+++ b/typescript/lib/lib.es5.d.ts	2019-10-25 12:34:11.071987865 +0200
@@ -1329,6 +1329,7 @@
       * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.
       * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
       */
-    reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
     reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
     /**
       * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.

In order to use reduce without initialValue on arrays for which it will work, it’s possible to introduce something that might or might not be along the lines of:

type NonEmptyArray<T> = [T, ...T[]];

This non-empty array type can safely reintroduce the reduce signature without initialValue, the very one I would like to retire from the (possibly empty) Array type.

People who want to live dangerously could still use ([] as NonEmptyArray).reduce(someOperation) if they absolutely refuse to provide an initialValue.

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
calimeroteknikcommented, Oct 25, 2019

In fact, there are no moments where there is no identity element, I wager. It would rather be the developer exploiting the mathematically clunky version of reduce (the one where you give no identity element that is).

To demonstrate, the above example,

arr.reduce((result, item) => result / item, /*no identity element*/);

…translates to English as “the first element of the list, divided by all others in turn”, a sentence where I notice the part “the first element of the list”, and which therefore leaves a gaping hole in the definition for the case of empty lists: it is not defined on them.

Emphasis on the fact that the first element is treated very differently from the rest, which should somehow be visible in the implementation. I believe the example is therefore more mathematically put as:

arr.slice(1).reduce((result, item) => result / item, arr[0]);

And the reference to the first element makes it clear as day that there will be a problem if we have nothing in the list.
…Although as it turns out, even tsc --strict doesn’t complain about it either and we get undefined. Well, technically, indeed. But, augh!

I believe that TS should only allow static references, e.g. arr[2] to array indexes that provably exist.
With the method mentioned earlier:

let foo: [T, T, T ...T[]] = [9, 12, 4, 5, 14, 7];
foo[0], foo[1]; // ok
foo[2]; // ok
foo[3]; // error

I explore this because the topic of arrays with some guarantees on their length isn’t irrelevant to in-depth handling of the present issue (which I’d very much like to explore solutions for).

1reaction
AnyhowStepcommented, Oct 25, 2019

Would be cool to have type guards like,

declare const arr : T[];
if (arr.length > 0) {
  //arr is now `[T, ...T[]]`
}
if (arr.length >= 2) {
  //arr is now `[T, T, ...T[]]`
}
if (arr.length == 4) {
  //arr is now `[T, T, T, T]`
}

This way, the overload for .reduce(this : [T, ...T[]], reducer) would be way easier to use.


I think there’s a proposal for such a type guard… I’m not sure.

[EDIT]

Found it

https://github.com/microsoft/TypeScript/issues/28837

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeError: Reduce of empty array with no initial value
The JavaScript exception "reduce of empty array with no initial value" occurs when a reduce function is used.
Read more >
Javascript Reduce an empty array - Stack Overflow
You cannot reduce an empty array unless you explicitly provide an initial "accumulated" value as the second argument: If no initialValue was ...
Read more >
JavaScript TypeError - Reduce of empty array with no initial ...
This error is raised if an empty array is provided to the reduce() method because no initial value can be returned in this...
Read more >
Using Array.reduce With Objects - RedBit Development
In Example 1, the initial value is 0. 2. The reduce statement in 'Example 1' will execute the callback function five times with...
Read more >
Reduce of empty array with no initial value error on Scroll
Seems like a bad "interaction" that is not being taking into account by the automatic code. If it is this, it would be...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found