我正在尝试为以下数据结构创建一个类型:
const columns = [
{
dataKey: 'field1',
label: 'Field 1',
render: ({ rowData, cellData }) => {
return null;
},
},
{
label: 'Actions',
render: ({ rowData }) => {
return null;
},
},
]
我不想用泛型类型来定义列,也不想在列表的每个对象中推断rowData和cellData的类型,如果dataKey不在对象中,cellData应该是未定义的。
当我指定dataKey时,rowData和cellData都显示为正确的类型,但如果没有它,rowData将变为any,但如果我输入任何不属于正确类型的值,typescript将报告错误,但不会推断正确的类型。
type ColumnDef<T, U> = {
label: string;
render: (args: { rowData: T; cellData: U }) => null;
};
type ColumnWithoutKey<T> = ColumnDef<T, undefined>;
type ColumnWithKey<T> = {
[K in keyof T]: T[K] extends infer TK
? { dataKey: K } & ColumnDef<T, TK>
: never;
}[keyof T];
type HasDataKey = {
dataKey: string;
};
type Column<T, U = any> = U extends HasDataKey
? ColumnWithKey<T>
: ColumnWithoutKey<T>;
type Columns<T> = Array<Column<T>>;
type Data = {
field1: string;
field2: number; // only work if I have two or more fields
};
const columns: Columns<Data> = [
{
dataKey: 'field1', // can autocomplete the dataKey values
label: 'Field 1',
// rowData type is Data and cellData is string, both are correct
render: ({ rowData, cellData }) => {
return null;
},
},
{
label: 'Actions',
// both rowData and cellData types are inferred as any
render: ({ rowData, cellData }) => {
return null;
},
},
{
label: 'Actions',
// will complain that field3 doesn't exist in the render type, but if I change it to field2, the type continues any
render: ({ rowData: { field3 } }) => {
return null;
},
},
];
Playground
1条答案
按热度按时间c9qzyr3d1#
只需在
ColumnWithoutKey
类型中添加一个显式(可选)dataKey
属性,类型为never
,这样Columns
类型就成为一个正确的可区分并集(具有dataKey
的列+具有未定义dataKey
的列):现在它按预期工作:
也适用于单个特性数据类型:
Playground链接
顺便说一句,你可以简化你的
ColumnWithKey
和Column
类型,在这些情况下不需要条件类型:Playground链接