Jared
Jared

Reputation: 2133

How to attach drag event handlers to a React component using TypeScript

I'm making my first foray into React (15.6.1) with TypeScript (2.4.2), and I'm trying to create a component that represents a JSON field which is draggable. Here is my component code:

import * as React from "react";

interface JsonFieldProps {
    name: string;
    type: string;
    indent: number;
}

export class JsonField extends React.Component<JsonFieldProps, undefined> {
    marginStyle = {
        'text-indent': `${this.props.indent * 15}px`
    };

    render() {
        return <div draggable={true} onDragStart={handleDrag} style={this.marginStyle}>{this.props.name}: {this.props.type},</div>;
    }
}

function handleDrag(ev: DragEvent): void {
    let id = (ev.target as HTMLDivElement).id;
    ev.dataTransfer.setData("text/plain", id);
}

When I try to compile it (using webpack), I get the following error:

ERROR in [at-loader] ./src/components/JsonField.tsx:15:21 
  TS2322: Type '{ draggable: true; onDragStart: (ev: DragEvent) => void;
    style: { 'text-indent': string; }; child...' is not assignable to type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.
  Type '{ draggable: true; onDragStart: (ev: DragEvent) => void; style: { 'text-indent': string; }; child...' is not assignable to type 'HTMLAttributes<HTMLDivElement>'.
    Types of property 'onDragStart' are incompatible.
      Type '(ev: DragEvent) => void' is not assignable to type 'EventHandler<DragEvent<HTMLDivElement>>'.
        Types of parameters 'ev' and 'event' are incompatible.
          Type 'DragEvent<HTMLDivElement>' is not assignable to type 'DragEvent'.
            Property 'initDragEvent' is missing in type 'DragEvent<HTMLDivElement>'.

I'm not sure if I'm using the wrong event type, but I can't seem to find any info about which one is correct if it is wrong.

Upvotes: 17

Views: 29457

Answers (1)

Amid
Amid

Reputation: 22352

You must use React.DragEvent interface instead of generic DOM DragEvent:

export class JsonField extends React.Component<JsonFieldProps, undefined>
{
    private marginStyle = {
        textIndent: `${this.props.indent * 15}px`
    };

    public render()
    {
        return (
            <div
                draggable={true}
                onDragStart={handleDrag}
                style={this.marginStyle}>
                {this.props.name}: {this.props.type}
            </div>);
    }
}

function handleDrag(ev: React.DragEvent<HTMLDivElement>): void
{
    const id = (ev.target as HTMLDivElement).id;
    ev.dataTransfer.setData("text/plain", id);
}

Note also change of text-indent to textIndent as you are using react and not pure html. Remember in react you are mainly working with virtual DOM, not real one - therefore all these changes.

As a side note I would recommend you to keep event handlers within class and not outside of it. This way you will be able to access class instance properties and methods.

Upvotes: 48

Related Questions