类型可分配给类型的约束,但可以使用约束的不同子类型进行实例化

问题描述 投票:0回答:1

我有这样的代码:

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'.

为什么会发生这种情况以及如何解决这个问题?

游乐场

reactjs typescript
1个回答
0
投票

出现该错误是因为 TypeScript 的类型系统默认是不变的,这意味着它不允许分配不同的类型。在您的情况下,

ContextValue<ItemWithId>
ContextValue<TData>
被认为是不同的类型,即使
TData
扩展了
ItemWithId

要解决此问题,您需要找到一种方法来告诉编译器

value
DataListContext
共享相同的类型。

其中一个想法是将构建上下文值的逻辑提取到可重用的通用挂钩中。然后,为每个 ContextValue 类型创建一个专用的 Root。由于你没有提到

Root
在你的项目中的使用,我无法说出拥有单一功能有多么重要。从实现细节来看,这是有道理的,因为您提供的上下文将始终缩小到您提供的
ContextValue
的通用类型(在您的情况下为
ContextValue<ItemWithId>
参见这个游乐场

如果这不适合您的实施策略,请分享有关 Root 使用的更多详细信息。您可能想重新考虑您的架构。

© www.soinside.com 2019 - 2024. All rights reserved.