Object is of type 'unknown'.ts(2571) in generic component

Viewed 669

I have a Table component with generics and I use a static component inside the Table to compose columns, also with generics.

The problem is that I would like the Column component to inherit the generic type passed to the Table when executing the data function, which gets the result passed to it.

I know typing explicitly will work, for example:

<Table.Column<TableItem> data={(item) => item.name} />

The real question is: Is it possible to perform this type inference from my Table component and pass it to the static Column component? So that I don't have to add the type explicitly to each column...

enter image description here

SANDBOX TO REPRODUCE, ONLY TABLE AND COLUMN COMPONENTS:

https://codesandbox.io/s/generic-table-column-r54lh?file=/src/App.tsx

2 Answers

You can specify the type for item:

<Table.Column<TableItem> data={(item:[type goes here]) => item.name} />

Few examples :

<Table.Column<TableItem> data={(item:any) => item.name} />

// or even
<Table.Column<TableItem> data={(item:{name:string;}) => item.name} />

There is an issue in your typing of children, namely that you are using ReactElement which does not include typing for the actual JSX function, just the returned element. You can see this in your example, by noting that the following covariant and contravariant children both pass, notwithstanding your children typing:

const MyDiv = (props:{myProp:string})=><div>{props.myProp}</div>

const App = () => {
  return (
    <Table<TableItem> keyExtractor={(item) => item.id} values={items}>
      <Table.Column header="Name" data={(item) => item.name} />
      <Table.Column header="Surname" data={(item) => item.surname} />
      <MyDiv myProp="me" />
      <div />
    </Table>
  );
};

BUT... I don't think that's really your underlying issue. The problem really is that you want Typescript to check that your children components are actually created via specific JSX with specific props, but, in fact, all Typescript will currently do is check that your JSX returns a valid JSX.Element. It won't check that the function that generated that JSX.Element satisfies a particular type or that the return type of that function is a specific kind of element with specific props.

This is a design limitation that is discussed in this open issue.

I think you could work around this by essentially defining your own custom prop that took in the props for Table.Column and then passed them to Table.Column inside your Table component. E.g, something like columnProps: ColumnProps<T> as a prop of Table. I'm not sure that would be any easier than just providing the explicit type to Table.Column, however.

Related