我试图制作严格类型的列构建器,但遇到了联合类型问题。我认为解决方案是将构建器返回类型推断为 (ColumnDef<Model, "Key1"> | ColumnDef<Model, "Key2>)[]
,但不知道如何实现这一点
...
type EnhancedCellRenderer<
Model extends AnyObject,
Field extends keyof Model = keyof Model & string
> = (props: EnhancedCellRenderProps<Model, Field>) => ReactNode
type CellRenderer<
Model extends AnyObject,
Field extends keyof Model = keyof Model & string
> = BasicCellRenderer<Model[Field]> | EnhancedCellRenderer<Model, Field>
interface ColumnDef<
Model extends AnyObject,
Field extends keyof Model = keyof Model & string
> {
width?: number | string
field: Field
renderer?: CellRenderer<Model, Field>
}
type ColumnBuilder<Model extends AnyObject> = <Field extends keyof Model>(
field: Field,
config?: Omit<ColumnDef<Model, Field>, 'field'>
) => ColumnDef<Model, Field>
declare function buildColumns<Model extends AnyObject>(
cb: (builder: ColumnBuilder<Model>) => ColumnDef<Model>[]
): ColumnDef<Model>[]
type Model = {
'01.20': number
'02.05': number
'02.20': number
'03.05': number
'03.20': number
'04.05': number
'04.20': number
}
buildColumns<Model>((builder) => [builder('01.20'), builder('02.05')])
我遇到了这个错误
Type 'ColumnDef<Model, "01.20">' is not assignable to type 'ColumnDef<Model, "01.20" | "02.05" | "02.20" | "03.05" | "03.20" | "04.05" | "04.20">'.
Types of property 'renderer' are incompatible.
Type 'CellRenderer<Model, "01.20"> | undefined' is not assignable to type 'CellRenderer<Model, "01.20" | "02.05" | "02.20" | "03.05" | "03.20" | "04.05" | "04.20"> | undefined'.
Type 'EnhancedCellRenderer<Model, "01.20">' is not assignable to type 'CellRenderer<Model, "01.20" | "02.05" | "02.20" | "03.05" | "03.20" | "04.05" | "04.20"> | undefined'.
Type 'EnhancedCellRenderer<Model, "01.20">' is not assignable to type 'EnhancedCellRenderer<Model, "01.20" | "02.05" | "02.20" | "03.05" | "03.20" | "04.05" | "04.20">'.
Type '"01.20" | "02.05" | "02.20" | "03.05" | "03.20" | "04.05" | "04.20"' is not assignable to type '"01.20"'.
答案 0 :(得分:1)
命名注意事项:泛型类型参数以conventionally的形式给出一两个大写字符的短名称,以便更容易地将它们与特定的类型名称区分开来。例如,看到 Model
既是特定类型又是泛型类型参数令人困惑。因此,在下文中,当用作类型参数时,我将使用 M
和 F
而不是 Model
和 Field
。
我不能声称已经仔细阅读了您的代码以了解它实际上试图做什么。尽管如此,我还是觉得您并不真正希望 ColumnDef<M>
成为适用于完整字段联合的单一事物,而是每个适用于单个领域的事物的联合。如果是这样,那么您可以在其 ColumnDef
参数中跨联合将 F
更改为 distribute:
type ColumnDef<M extends AnyObject, F extends keyof M = keyof M> =
F extends keyof M ? {
width?: number | string
field: F
renderer?: CellRenderer<M, F>
} : never;
如果您检查 ColumnDef<Model>
,您会发现它现在是联合类型:
type ColumnDefModel = ColumnDef<Model>;
/* type ColumnDefModel = {
width?: string | number | undefined;
field: "01.20";
renderer?: CellRenderer<Model, "01.20"> | undefined;
} | {
width?: string | number | undefined;
field: "02.05";
renderer?: CellRenderer<...> | undefined;
} | ... 4 more ... | {
...;
} */
您的 buildColumns()
调用不再出错:
buildColumns<Model>((builder) => [builder('01.20'), builder('02.05')])