[英]Typescript and React: How to dynamically infer types from the parent component?
I have a generic component that I use to build specific tables along the code.我有一个通用组件,用于沿代码构建特定表。 Let's call it
GenericTable
.我们称之为
GenericTable
。 Its workflow looks like this:它的工作流程如下所示:
Table Rendering Workflow表格渲染工作流程
In order to simplify the question, let's say the GenericTable
has only two props: columns
and rows
.为了简化问题,假设
GenericTable
只有两个道具: columns
和rows
。
export const Page1 = () => {
return (
<GenericTable
columns={page1Columns}
rows={page1Rows}
/>
);
};
export const Page2 = () => {
return (
<GenericTable
columns={page2Columns}
rows={page2Rows}
/>
);
};
Let's say that the types of the columns
and rows
may vary from page to page.假设
columns
和rows
的类型可能因页面而异。 For instance, Page1
may have a table only showing numbers while Page2
may have a more sophisticated table with strings, numbers and even other components.例如,
Page1
可能有一个只显示数字的表格,而Page2
可能有一个更复杂的表格,其中包含字符串、数字甚至其他组件。 This way, the properties
and types
of the GenericTable
should look something like this:这样,
GenericTable
的properties
和types
应该如下所示:
type GenericTableProps<ColumnType, RowType> {
columns: ColumnType;
rows: RowType;
}
export const GenericTable = <
ColumnType extends Page1ColumnType | Page2ColumnType,
RowType extends Page1RowType | Page2RowType
>(
props: GenericProps<ColumnType, RowType>
) => {
// build the table here using the columns and rows props
}
The problem here is, since I may have more than just twos pages calling the GenericTable
, I do not want to hard code the types such as Page1ColumnType
, Page1RowType
and so on.这里的问题是,由于我可能有不止两个页面调用
GenericTable
,我不想硬编码Page1ColumnType
、 Page1RowType
等类型。 How can I dynamically infer the columns and rows type from the page that is passing it?如何从传递它的页面动态推断列和行类型?
For example, in case a Page3
calls in the GenericTable
, how can it infer that the ColumnType
will extend the Page3ColumnType
without hardcoding it.例如,如果
Page3
在GenericTable
中调用,它如何推断ColumnType
将扩展Page3ColumnType
而无需对其进行硬编码。
COnsider this example:考虑这个例子:
type Page1ColumnType = {
tag: 'Page1ColumnType'
}
type Page2ColumnType = {
tag: 'Page2ColumnType'
}
type Page1RowType = {
tag: 'Page1RowType'
}
type Page2RowType = {
tag: 'Page2RowType'
}
type GenericTableProps<ColumnType, RowType> = {
columns: ColumnType;
rows: RowType;
}
export const GenericTable = <
ColumnType extends Page1ColumnType | Page2ColumnType,
RowType extends Page1RowType | Page2RowType
>(
props: GenericTableProps<ColumnType, RowType>
) => { }
Type signature of GenericTable
is unsafe, because ColumnType
and RowType
are not related/binded to each other. GenericTable
的类型签名是不安全的,因为ColumnType
和RowType
彼此不相关/不绑定。 It means that this call is perfectly valid from typescript point of view:这意味着从 typescript 的角度来看,这个调用是完全有效的:
const result = GenericTable({
columns: {
tag: 'Page1ColumnType'
},
rows: {
tag: 'Page2RowType'
}
})
Have you noticed that columns are Page1
and rows are Page2
.您是否注意到列是
Page1
和行是Page2
。 In order to bind columns and rows, you need to make it as a part of one data structure:为了绑定列和行,您需要将其作为一个数据结构的一部分:
type GenericTableProps<ColumnType, RowType> = {
columns: ColumnType;
rows: RowType;
}
type DataStructure =
| GenericTableProps<Page1ColumnType, Page1RowType>
| GenericTableProps<Page2ColumnType, Page2RowType>
export const GenericTable = (
props: DataStructure
) => { }
// ERROR
GenericTable({
columns: {
tag: 'Page1ColumnType'
},
rows: {
tag: 'Page2RowType' // wrong value
}
})
// OK
GenericTable({
columns: {
tag: 'Page1ColumnType'
},
rows: {
tag: 'Page1RowType' // ok
}
})
If you don't want to hardcode all allowed states up front, you still need to some how map types.如果您不想预先对所有允许的状态进行硬编码,您仍然需要了解 map 的类型。 If you will provide me with expected interface of row and column I try to write generic function, because I don't know the shape of row and column and how they are related between each other
如果你会给我提供预期的行和列接口,我会尝试编写通用 function,因为我不知道行和列的形状以及它们之间的关系
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.