我有这样的代码:
type ItemWithId = { id: string }
type Column<TData extends ItemWithId> = {
label: string
sortable?: boolean
render: (item: TData, items: TData[]) => ReactNode
}
type ColumnsBuilder<TData extends ItemWithId> = {
build: (options: Column<TData>) => Column<TData>
}
type ContextValue<TData extends ItemWithId> = {
columns: Column<TData>[]
items: TData[]
}
const DataListContext = createContext<ContextValue<ItemWithId> | undefined>(undefined)
type RootProperties<TData extends ItemWithId> = PropsWithChildren<{
items: TData[]
getColumns: (builder: ColumnsBuilder<TData>) => Column<TData>[]
}>
export function Root<TData extends ItemWithId>(properties: RootProperties<TData>) {
const { items, getColumns, children } = properties
const columns = useMemo(() => {
return getColumns({
build(options: Column<TData>) {
const { sortable = false, ...restOptions } = options
return {
...restOptions,
sortable,
}
},
})
}, [getColumns])
const value = useMemo(() => {
return {
columns,
items,
}
}, [columns, items])
return <DataListContext.Provider value={value}>{children}</DataListContext.Provider>
}
在声明中
<DataListContext.Provider value={value}
我收到错误:
Type '{ columns: Column<TData>[]; items: TData[]; }' is not assignable to type 'ContextValue<ItemWithId>'.
Types of property 'columns' are incompatible.
Type 'Column<TData>[]' is not assignable to type 'Column<ItemWithId>[]'.
Type 'Column<TData>' is not assignable to type 'Column<ItemWithId>'.
Type 'ItemWithId' is not assignable to type 'TData'.
'ItemWithId' is assignable to the constraint of type 'TData', but 'TData' could be instantiated with a different subtype of constraint 'ItemWithId'.
为什么会发生这种情况以及如何解决这个问题?
出现该错误是因为 TypeScript 的类型系统默认是不变的,这意味着它不允许分配不同的类型。在您的情况下,
ContextValue<ItemWithId>
和 ContextValue<TData>
被认为是不同的类型,即使 TData
扩展了 ItemWithId
。
要解决此问题,您需要找到一种方法来告诉编译器
value
和 DataListContext
共享相同的类型。
其中一个想法是将构建上下文值的逻辑提取到可重用的通用挂钩中。然后,为每个 ContextValue 类型创建一个专用的 Root。由于你没有提到
Root
在你的项目中的使用,我无法说出拥有单一功能有多么重要。从实现细节来看,这是有道理的,因为您提供的上下文将始终缩小到您提供的 ContextValue
的通用类型(在您的情况下为 ContextValue<ItemWithId>
)参见这个游乐场。
如果这不适合您的实施策略,请分享有关 Root 使用的更多详细信息。您可能想重新考虑您的架构。