Given the following, the parameter value of the render method is typed as string | number.
How can I make sure that it gets typed as T[dataIndex], which is string in case dataIndex: 'name', and number in case dataIndex: 'id'?
import * as React from 'react'
type Col<T extends object, K extends keyof T> = {
title: string;
dataIndex: K;
render: (value: T[K]) => React.ReactNode;
};
function Tab<T extends object, K extends keyof T = keyof T>(list: T[], cols: Col<T, K>[]): JSX.Element {
return (
<table>
<thead>
<tr>
{cols.map(col => (
<th key={col.title}>{col.title}</th>
))}
</tr>
</thead>
<tbody>
{list.map((item, i) => (
<tr key={i}>
{cols.map(col => (
<td key={col.title} children={col.render(item[col.dataIndex])} />
))}
</tr>
))}
</tbody>
</table>
);
}
Tab(
[
{ id: 1, name: 'Hello' },
{ id: 2, name: 'World' }
],
[
{
title: 'Name',
dataIndex: 'name',
render: value => <span>{value.length}</span>
},
{
title: 'Id',
dataIndex: 'id',
render: value => <span>{value}</span>
}
]
);
You need an extra type parameter to the component to capture the actual keys that are actually used as a tuple. You can then use a mapped type to map it to the array of columns, Typescript will be able to follow the reverse mapping and infer
Kfrom the array and then go back and correctly type the parameters.Playground Link