简体   繁体   中英

Creating a Generic React Forward Ref component unassignable to the constraint

I'm trying to create a Generic Forward Ref component that accepts a value of generic type and a render function that also needs a value property from that same generic type .

I get the Typescript error: TS2322: Type 'Product' is not assignable to type 'T'. 'Product' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Draggable'. TS2322: Type 'Product' is not assignable to type 'T'. 'Product' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Draggable'. (L34 @ https://github.com/pieterjandebruyne/generic-forward-ref-issue/blob/master/src/GenericForwardRefComponent.tsx )

I already found some posts on stack overflow explaining what and why it could go wrong but still I feel that none of the explanations really apply to this usecase..

I created a public repo to recreate the issue @ https://github.com/pieterjandebruyne/generic-forward-ref-issue

Files that are being used are:

  • App.tsx -> calls the GenericForwardRefComponent
  • GenericForwardRefComponent.tsx -> should render the ProductRow and pass the generic type
  • Interfaces.ts -> all types
  • ProductRow.tsx -> component that should be rendered

The ultimate goal is that I could also have for example a CategoryRow (with value of type Category (that has id: string )) that I could pass to the GenericForwardRefComponent

Is this something that would be possible or am I just trying to stretch the current limits of React/TS? Also I would love to hear an explanation why this error occurs as I don't see the error that could happen with this implementation. This stackoverflow probably addresses this but I can't figure out why/which part triggers it in my code.. How to fix TS2322: "could be instantiated with a different subtype of constraint 'object'"?

I used the generic forward ref approach I found @ https://dirask.com/posts/React-forwardRef-with-generic-component-in-TypeScript-D6BoRD

You can see that with this inside the function with this header

const x = <T extends Draggable>(
        {
            dragOverlay,
            renderItem,
            value
        }: GenericForwardedRefComponentProps<T>,
        reference: ForwardedRef<HTMLDivElement>
    )

you call this function:

        return renderItem({
            value,
            reference
        })

If i simplify, the renderItem has type (value: T) =>... but then in the body, the type of value is always Product .

When the function would be called with T = Product , that would work fine, but consider, that the caller of this function can call the function with T = MyType like this:

interface MyType extends Draggable {
    my_prop: string
} 
x<MyType>({ renderItem: (x: MyType) => { x.my_prop }, value: { name: "XXX" } })

You can see, that in the function renderItem I'm accessing a field, that is not present in the product type. That's why there is this error. I have fulfilled the contract of the function, but the result is that I'm accessing missing fields.

Anyway, the function is called only once, so you can remove the type parameter and like this:

    (
        {
            dragOverlay,
            renderItem,
            value
        }: GenericForwardedRefComponentProps<Product>,
        reference: ForwardedRef<HTMLDivElement>
    ) => {

Then, typescript will be satisfied.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM