我正在尝试改进react-table的类型定义,并且遇到了绊脚石。该库具有极好的可扩展性,它提供钩子/插件来扩展库的几乎任何部分。对于用户来说,这太棒了,但是在尝试编写类型时却非常具有挑战性。
例如,主api返回一个表实例对象,该对象公开了列,行,单元格等。这些对象又提供了可在呈现表时使用的api,并且这些api还提供了对对象的各个相关部分的访问层次结构。初始api配置了一系列插件,这些插件可以扩展任何这些对象的内容。
当前,我使用接口和声明合并来解决所有这些问题,它可以工作,但是由于这需要全局定义,因此很难使用几种不同的表配置。
逻辑方法是根据所使用的插件扩展返回的类型。
问题1
这看起来很有希望,我得到的代码可以很好地提取插件数组的相关位。
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never
type PluginConfig = {
instance?: unknown
cell?: unknown
}
type Plugins = PluginConfig[]
type ArrayPick<T extends Plugins, K extends keyof T[number]> = T[number][K]
type PluginEnhancements<P extends Plugins, K extends keyof P[number]> = UnionToIntersection<
NonNullable<ArrayPick<P, K>>
>
type Plugin1<D extends object, P extends Plugins = []> = PluginConfig & {
instance: { p1: string, rows: Array<Row<D,P>> }
}
type Plugin2<D extends object, P extends Plugins = []> = PluginConfig & {
instance: { p2: string }
}
type Enhancements = PluginEnhancements<[Plugin1<Data>, Plugin2<Data>], 'instance'>
得出的结果是:
type Enhancements = {
p1: string;
rows: {
cells: {
column: ColumnInstance<Data, []>;
row: ...;
}[];
}[];
p2: string;
}
那很好,但是有一个问题,因为Row
类型本身需要使用中的插件的知识,因此定义变得递归,因为每个插件确实需要将插件列表传递给PluginEnhancements
。 / p>
我真的不确定是否有办法解决这个问题。
问题2
理想情况下,我希望传递给各种功能的插件对象列表隐含插件列表的类型,而无需为每种类型创建单独的类型,而这会使接口混乱。
该库(使用javascript)公开了看起来像这样的插件:
export const usePagination: <D extends object, P extends Plugins>(hooks: Hooks<D, P>) => void
我天真地以为我可以做这样的事情:
export type PluginHook<D extends object, P extends Plugins> = {
(hooks: Hooks<D, P>): void
}
type usePagination<D extends object, P extends Plugins> =
PluginConfig &
PluginHook<D, P> & {
instance: UsePaginationInstanceProps<D, P>
}
export const usePagination: usePagination // <- doesn't work
但是随后我遇到了问题,因为您无法声明通用的const。我确实看到了Declaring const of generic type,但是那里的解决方案虽然确实适用于函数声明,但是只是将相同的问题移至instance
属性。
我怀疑我只是为执行此操作选择了错误的方法。我认为,简单地增强现有插件的定义会很简单,但是也许有更好的方法将相关配置与方法相关联。
这是一个同时包含这两种内容以及一些支持类型的打字机游乐场:typescript playground
我真的很感谢这里的任何建议,当我唯一的问题是我缺乏知识时,我不愿意放弃这个作为失败的事业。