Reduce without an initialValue should be illegal on a potentially empty array
See original GitHub issueTypeScript 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:
- Created 4 years ago
- Comments:6 (4 by maintainers)
Top GitHub Comments
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,
…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:
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 getundefined
. 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:
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).
Would be cool to have type guards like,
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