网站搜索

javascript - 对象的类型为 'unknown'。ts(2571) 在通用组件中


我有一个带有泛型的表格组件,并且我在表格内部使用一个静态组件来组成列,这个静态组件也使用泛型。

问题是,我希望 Column 组件在执行 data 函数时继承传递给 Table 的通用类型,该函数会接收传递给它的结果。

我知道显式打字会起作用,例如:

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

真正的问题是:是否有可能从我的 Table 组件执行这种类型推断,并将其传递给静态的 Column 组件?这样我就不必为每一列显式地添加类型……

用于重现的沙箱,仅限表和列组件:

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

答案#1

你可以为 item 指定类型:

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

一些例子:

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

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

答案#2

你的 children 类型存在一个问题,也就是你使用了 ReactElement,它不包括对实际 JSX 函数的类型定义,只包含返回的元素。你可以在你的示例中看到这一点,通过注意以下协变和逆变的 children 都能通过,尽管你的 children 类型如此定义:

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>
  );
};

但是……我认为这并不是真正影响你的根本问题。真正的问题是你希望 TypeScript 检查你的子组件是否确实是通过具体的 JSX 和具体的 props 创建的,但事实上,TypeScript 当前唯一会做的就是检查你的 JSX 返回的是一个有效的 JSX.Element。它不会检查生成该 JSX.Element 的函数是否符合某种类型,也不会检查该函数的返回类型是否是具有特定 props 的特定类型的元素。

这是在这个公开问题中讨论的设计限制。

我认为你可以通过本质上定义你自己的自定义 prop 来解决这个问题,该 prop 接收 Table.Column 的 props,然后将它们传递给你的 Table 组件中的 Table.Column。例如,可以像 columnProps: ColumnProps<T> 这样作为 Table 的一个 prop。不过,我不确定这是否会比直接为 Table.Column 提供显式类型更容易。