I am trying to dynamically render a table in react. The generic attributes will ensure indexing elements of the data array dynamically (At least i though so). I would also like to only be able to pass keys of Type T to the columns parameter. Therefore getting rid of the generics is not an option here. I also used the Extract type in order to render the columns separately, but excluding it makes no difference.
function Table<T, Key extends keyof T>({
data,
columns,
}: {
data: T[];
columns: Extract<Key, string>[];
}) {
return (
<div>
{data.map((row) => (
<tr>
{columns.map((col) => (
<td>{row[col]}</td> //this is where the error appears
))}
</tr>
))}
</div>
);
}
This will generate following error:
Type 'T[Extract<Key, string>]' is not assignable to type 'ReactNode'.
Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactNode'.
Type 'T[string]' is not assignable to type 'ReactNode'.
Type 'T[string]' is not assignable to type 'ReactPortal'.
Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactPortal'.
Type 'T[Extract<Key, string>]' is not assignable to type 'ReactPortal'.
Type 'T[Extract<keyof T, string>]' is not assignable to type 'ReactPortal'.
Type 'T[string]' is not assignable to type 'ReactPortal'.ts(2322)
In order to isolate the error i tried to reproduce the error using simple dynamic indexing and generic constraints:
function getKeyOfT<T, Key extends keyof T>(array: T[], key: Key) {
return array[key];
}
Following error is generated:
Type 'keyof T' cannot be used to index type 'T[]'.ts(2536)
I have already looked at several answers, but they seemed to be different and their solutions did not seem to cover my issue:
- Type '"test"' cannot be used to index type 'T'
- Type 'K' cannot be used to index type '{ [key in keyof K]: V; }'.ts(2536)
- Type '1' is not assignable to type 'T[Extract<keyof T, string>]'
As some of them suggested, asserting the type should solve the issue. However this seems to be redundant in this case:
function getElementOfArray<T, Key extends keyof T>(array: T[], key: Key) {
return array[key as keyof T];
}
CodePudding user response:
When you tried to isolate the error, the error message changed because it is a different error.
To solve your original error:
Type 'T[Extract<Key, string>]' is not assignable to type 'ReactNode'
This just means that TypeScript does not know what kind of content is inside T
but it expects something assignable to ReactNode
.
I would try to modify the definition of your function to:
function Table<T extends Record<string, ReactNode>, Key extends keyof T>({
data,
columns,
}: {
data: T[];
columns: Extract<Key, string>[];
}) {
return (
<div>
{data.map((row) => (
<tr>
{columns.map((col) => (
<td>{row[col]}</td> //this is where the error appears
))}
</tr>
))}
</div>
);
}