Reputation: 366
I made a custom table React component that helps me present several arrays of maps with different fields defined written in JavaScript, I'm moving my code base to Typescript to leverage types but I'm having issues with this component, I decided to use generics but I'm facing issues with that too in regard to tsc
:
Argument of type 'string' is not assignable to parameter of type 'keyof T'. Type 'string' is not assignable to type '"idx" | "ID"'.
Here is a minimal example that reproduces what I see with the code of my component:
import React from 'react'
interface MyTableProps<T> {
arr: Array<T>
fields: Array<string>
}
const getProperty = <T, K extends keyof T>(obj: T, key: K) => {
return obj[key]
}
const MyTable = <T extends { idx?: string | number; ID?: string | number }>({ arr, fields }: MyTableProps<T>) => {
return (
<table>
<thead>
<tr>
{fields.map(field => (<th key={field}>{field}</th>))}
</tr>
</thead>
<tbody>
{arr.map(row => (
<tr key={row.idx || row.ID}>
{
fields.map(field => (
<td key={"td"+field}>{getProperty(row, field)}</td>
))
}
</tr>
))}
</tbody>
</table>)
}
The error quoted above comes from the getProperty
function second argument.
My question is: What should I do to have a dynamic generic type for the prop argument in my React component?
Upvotes: 0
Views: 1431
Reputation: 1189
It is recommended to use these patterns, from the React TypeScript Cheatsheet. You can find useful things about how to wrap components with generic HTML element props. In few words, it states that it is better to use the React.ComponentPropsWithoutRef
or React.ComponentPropsWithRef
(if you want to pass a ref to the component). Here is a part of their examples:
// usage
function App() {
// Type '"foo"' is not assignable to type '"button" | "submit" | "reset" |`undefined'.(2322)
// return <Button type="foo"> sldkj </Button>
// no error
return <Button type="button"> text </Button>;
}
// implementation
export interface ButtonProps extends React.ComponentPropsWithoutRef<"button"> {
specialProp?: string;
}
export function Button(props: ButtonProps) {
const { specialProp, ...rest } = props;
// do something with specialProp
return <button {...rest} />;
}
Upvotes: 1
Reputation: 14078
Try using this for MyTableProps<T>
:
interface MyTableProps<T> {
arr: Array<T>
fields: Array<keyof T>
}
Upvotes: 1