I'm trying to figure out how to type this fmap
function I have. Here's my latest attempt:
export const __skip__ = Symbol('skip');
type ReduceFn<T> = Array<T>['reduce']
/**
* Filter-map. Like map, but you may omit entries by returning `__skip__`.
*/
export function fmap<TVal,TReturn>(this:TVal[], callback: (this: TVal[], ...args:[currentValue: TVal, index: number])=>TReturn|typeof __skip__): TReturn[] {
return Array.prototype.reduce.call(this, (accum: TReturn[], ...args) => {
let x = callback.call(this, ...args);
if (x !== __skip__) {
accum.push(x);
}
return accum;
}, []);
}
Even though it knows what callback
returns:
How come? How do I fix the errors?
N.B. I typed args
as [currentValue: TVal, index: number]
to try to simplify a bit, but I think it should be Parameters<ReduceFn<TVal>>
Also, I know the signature is a bit funny. The usage of this
is intentional for legacy reasons.
Here's an example usage:
const keys = fmap.call(feeIds, id => feeIdToKey[id] || __skip__)
CodePudding user response:
Seems like the method Array.prototype.reduce.call
is trying to infer the type automatically based on the generic type of Array
, but is unable to infer it properly since the default generic type of Array
is any
(that is Array<any>
). But you can pass in whichever generic type you want to the method call
, manually, rather than relying on the automatic inference in this specific instance.
Here's how you can do it:
export function fmap<TVal, TReturn>(this: TVal[], callback: (this: TVal[], ...args: [currentValue: TVal, index: number, array: TVal[]]) => TReturn | typeof __skip__): TReturn[] {
return Array.prototype.reduce.call<
// Here's our manually passed in generic type
TVal[], [callbackfn: (previousValue: TReturn[], currentValue: TVal, currentIndex: number, array: TVal[]) => TReturn[], initialValue: TReturn[]], TReturn[]
>(this, (accum: TReturn[], ...args) => {
let x = callback.call(this, ...args);
if (x !== __skip__) {
accum.push(x);
}
return accum;
}, []);
};
NOTE
I also had to add the parameter array: TVal[]
to this line: callback: (this: TVal[], ...args: [currentValue: TVal, index: number, array: TVal[]]) => TReturn | typeof __skip__
, since Array.prototype.reduce
's callback param expects also a fourth, array
, parameter.