Alright so don't ask why but I am trying to implement a reduce method on subclass of Map:
class MapArray<A, B> extends Map<A, B> {
reduce<T = [A, B]>(f: (prev: T, next: [A, B]) => any, initialVal?: T) {
let prev = arguments.length > 1 ? arguments[1] : nah;
let index = 0;
for (const [k, v] of this) {
if (prev === nah) {
prev = [k, v];
continue;
}
prev = f(prev, [k, v]);
}
return prev;
}
}
it's not the prettiest thing, but it basically works. The problem is the typing. If I do:
new MapArray<string,boolean>().reduce((a,b) => 'whatever');
versus:
new MapArray<string,boolean>().reduce((a,b) => 'whatever', []);
I want it to able to capture the type of the 2nd argument []
using my invalid version of TS, I tried something like this:
type X = (if initialVal ? typeof initialVal : [A, B])
reduce<R = any, T = X>(f: (prev: T, next: [A, B]) => R, initialVal?: T);
this is obviously completely wrong, but hopefully you get the idea, doubt it's possible though. Does anyone know if I can capture the type of initialVal
if it's passed, and if not, default to [A,B]
?
here is the problem: TS playground
It will compile but "a is not iterable" (a as in first argument to the reduce callback)...a is not iterable because a is 55.
CodePudding user response:
A solution may be to use undefined
instead of your nah
and method overloading:
class MapArray<A, B> extends Map<A, B> {
reduce(f: (prev: [A, B], next: [A, B]) => any): [A, B];
reduce<T>(f: (prev: T, next: [A, B]) => any, initialVal: T): T;
reduce<T>(f: (prev: T | [A, B], next: [A, B]) => any, initialVal?: T) {
let prev: [A, B] | T | undefined = initialVal;
let index = 0;
for (const [k, v] of this) {
if (prev === undefined) {
prev = [k, v];
continue;
}
prev = f(prev, [k, v]);
}
return prev;
}
}
new MapArray<string,boolean>().reduce((a,b) => 'whatever');
new MapArray<string,boolean>().reduce((a,b) => 'whatever', []);
I see that this is quite similar to @Alexander Mills solution.
This is intended to be as close as possible with your original code, but I would like to point out that the return type of the function f
should be the same as prev
and in this case the returned value of your example function (the string
"whatever"
)doesn't work out.
CodePudding user response:
This doesn't 100% answer the original question, but it might help someone.
A partial solution is to use overloads like so:
reduce<R = any>(f: (prev: [A, B], next: [A, B]) => R): R;
reduce<R = any, T = any>(f: (prev: T, next: [A, B]) => R, initialVal?: T) {...}
the reason this doesn't really serve as an answer to OP is that I would like to grab the user-supplied type of initial val, instead of having to declare it with the generics parameter.
So again, looking to do something like:
reduce<R = any>(f: (prev: [A, B], next: [A, B]) => R): R;
reduce<R = any, T = typeof initialVal>(f: (prev: T, next: [A, B]) => R, initialVal?: <T>) {...}