Home > database >  Type 'number' is not assignable to type '(Record<P, unknown> & Record<S, num
Type 'number' is not assignable to type '(Record<P, unknown> & Record<S, num

Time:10-14

I thought this error was strange to see, since intuitively you would expect number and Record<A, number>[A] to be compatible, and therefore also (B & Record<A, number>)[A]. I'm not sure what causes this, so it's hard to make a more minimal example. But I'll include some more context below:

This error appeared when I was making a function for aggregating table data, summing over specific columns. The table data is an array of objects, all with the same keys, although these keys are all unknown at compile time.

However, the table data is split into columns that are to be summed, and columns that are to be constant. So the row needs to be typed as a union of Records.

I was wanting to type this function generically so that it would work on arbitrary data, and also to have as arguments which columns to group by and which to sum over, also working as a filter. Here's a fairly minimal example that causes the same error:

//type P = 'a' | 'b' | 'c';
//type S = 'x' | 'y' | 'z';
//const aggregateRows = (
type RecordKeys = string | number | symbol;
const aggregateRows = <P extends RecordKeys, S extends RecordKeys>(
    otherCols: P[],
    numberCols: S[],
    rows: (Record<P, unknown> & Record<S, number>)[],
): void => {
    rows[0][numberCols[0]]  = 1;  // <--- ERROR in question
}

(link to playground)

Somewhat oddly, when I tried to simplify by avoiding generics, defining P and S outside the function to be non-overlapping string literals, the error just went away (see the commented out lines). Am I doing something wrong?

Any help would be appreciated.

CodePudding user response:

I did find a way to get the error to go away:

rows[0][numberCols[0]] = (
    rows[0][numberCols[0]]   1 as (Record<P, unknown> & Record<S, number>)[S]
);

However, I'm pretty sure this is caused by an error in my typing, making typescript too strict in what it will accept as the contents of the rows object. I think that should be fixed instead, rather than working my way around the error, but I don't know what I'm doing wrong.

CodePudding user response:

you can try the following, hope that helps

type RecordKeys = string | number | symbol;
const aggregateRows = <P extends RecordKeys, S extends RecordKeys>(
    otherCols: P[],
    numberCols: S[],
    rows: Record<P, unknown | number>[],
): void => {
    (rows[0] as any)[numberCols[0]]  = 1;
}

playground

  • Related