我似乎找不到一种动态的方法来使dataItem
总是与field
属性的值具有相同的类型。在下面的示例中,dataItem
总是string | Date | number
,而不是取决于field
属性的特定类型。
interface TableColumn<D> {
field: keyof D
renderCell: (dataItem: D[keyof D]) => ReactNode
}
interface Data {
foo: string
bar: Date
fiz: number
}
const data: Data = {
foo: "my foo",
bar: new Date(),
fiz: 32
}
const tableColumn: TableColumn<Data> = {
field: "foo",
renderCell: (dataItem) => dataItem // here dataItem should be string only
}
const tableColumn1: TableColumn<Data> = {
field: "bar",
renderCell: (dataItem) => dataItem // here dataItem should be Date only
}
const tableColumn2: TableColumn<Data> = {
field: "fiz",
renderCell: (dataItem) => dataItem // here dataItem should be number only
}
1条答案
按热度按时间o8x7eapl1#
一个接口不会这样工作;你可以把它设置得更像generic,比如
TableColumn<D, K>
,其中K
是keyof D
中的一个特殊的键类型,但是你必须在所有地方都指定K
。相反,我将使
TableColumn<D>
成为microsoft/TypeScript#47109中创造的 * 分布式对象类型 *,它求值为与keyof T
中的每个K
相对应的各个类型的并集。分布式对象类型是mapped type,它将keyof D
中的每个属性值K
转换为保存与该属性键相对应的所需类型的值。然后直接得到indexed into和keyof D
,就像这样:在这里,我们生成Map类型
{ [K in keyof D]-?: { field: K, renderCell: (dataItem: D[K]) => ReactNode }}
,对于Data
,它变为如下形式注意,Map修饰符
-?
只是确保D
中的任何可选属性在Map类型中成为必需的,因为我们不希望任何undefined
在这里浮动。然后,我们通过
{...}[keyof D]
索引到该类型,它将Map的类型转换为其值类型的并集,最终生成:这就是您想要的联合类型;实际上,它是一个判别并集,其中
field
是判别属性,它允许编译器从field
的类型推断出renderCell
的类型,从而在renderCell
的未注解回调参数上给出所需的上下文类型:Playground代码链接