Home > database >  How to infer type in this component setup?
How to infer type in this component setup?

Time:10-17

I have an item object that I collect from this custom hook (from React DnD). The problem is that typescript doesn't allow me to access its property in the drop function below, because its type is unknown.

function MyComponent(props){

   const [{item}, drop] = useDrop({
        accept: "BLOCK",
        collect: monitor => ({
            item: monitor.getItem() // Item object collected here IDropTargetMonitor
        }),
        drop: (): void => setBlock_name(item.block_name) // /!\ Object [item] is of type 'unknown'
    })

  return ...
}

The corresponding interface in the module is the following :

export interface DropTargetMonitor<DragObject = unknown, DropResult = unknown>

I define what I want in the item object here :


const OtherComponent = (props) => {

    const [{isDragging}, drag] = useDrag({
        type: "BLOCK",
        item: {blockName: props.blockName}, // blockName is a string
        collect: monitor => ({
            isDragging: monitor.isDragging()
        })
    })

    return ...
}

I would be grateful if someone could give me an hint on how I could infer the item type.

CodePudding user response:

There are some things that can be adjusted from your code. useDrop is a generic that accepts the types for the dragged item. It's defined as:

 useDrop<DragObject = unknown, DropResult = unknown, CollectedProps = unknown>

You could create an interface for your item:

interface Item {
  blockName: string;
}

and then refactor your useDrop hook like:

const [{item}, drop] = useDrop<Item, unknown, {item: Item}>({
    accept: "BLOCK",
    collect: monitor => ({
        item: monitor.getItem() 
    }),
    drop: (item: Item): void => setBlock_name(item.blockName)
})

This way Typescript will know that item is of type Item. A couple things to notice is that in your code you had setBlock_name(item.block_name) but it should be setBlock_name(item.blockName) since in your useDrag you used item: {blockName: props.blockName} so the property name is blockName instead of block_name. The other thing is that if you're gonna use the dropped item in your drop method in useDrop you should use the one that is passed as the first argument for drop: (item) => void, you don't need to capture item in the collect function. Hope this helps you.

  • Related