I have this sumBy
function that looks like this:
export function sumBy<T>(array: T[], mapperFn: (item: T) => number): number {
return array.reduce((sum, currentItem) => sum + mapperFn(currentItem), 0);
and I wanted to improve it to accept also bigint
type.
But of course, I have to tell the +
operator, as well as the initialiser their proper type. For the latter, I have a clean solution (if (sum === undefined) return currentValue;
), but for the former, I can't find a proper way. My best guess for now is this:
export function sumBy<T, U extends number | bigint>(array: T[], mapperFn: (item: T) => U): U | undefined {
return array.reduce((sum: U | undefined, currentItem: T) => {
const currentValue = mapperFn(currentItem);
if (sum === undefined) return currentValue;
if (typeof currentValue === "number" && typeof sum === "number") return (sum + currentValue) as U;
if (typeof currentValue === "bigint" && typeof sum === "bigint") return (sum + currentValue) as U;
}, undefined);
}
But this is so heavy, and it doesn't even return the expected type for empty array ...
How come I can't:
+
operatorsumBy<T, U is number or bigint>(array: T[], mapperFn: (item: T) => U): U
Thanks!
I would use function overloads here to match the input and output:
const ensureBigint = (val: number | bigint): bigint => typeof val === 'number' ? BigInt(val) : val;
function sumBy(array: [], mapperFn: (item: any) => any): undefined;
function sumBy<T>(array: [T, ...T[]], mapperFn: (item: T) => number): number;
function sumBy<T>(array: T[], mapperFn: (item: T) => number): number | undefined;
function sumBy<T>(array: [T, ...T[]], mapperFn: (item: T) => number | bigint): bigint;
function sumBy<T>(array: T[], mapperFn: (item: T) => number | bigint): bigint | undefined;
function sumBy<T>(array: T[], mapperFn: (item: T) => number | bigint): number | bigint | undefined {
if(!array.length) return undefined;
let sum: bigint | number = 0;
for(const item of array){
const val = mapperFn(item);
if (typeof val === "number" && typeof sum === 'number'){
sum = sum + val;
continue;
}
sum = ensureBigint(sum) + ensureBigint(val);
}
return sum;
}
const s = sumBy([{num:0n}, {num:1}], item => item.num); // bigint
console.log(s);
const s2 = sumBy([1, 1], item => item); // number
console.log(s2);
const s3 = sumBy([], item => item); // undefined;
console.log(s3);
const arr = [1, 2n];
arr.length = 0;
const s4 = sumBy(arr, item => item); // bigint | undefined