You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript版ReactDnd示例求助:在线Babel语法示例不兼容TypeScript2.1

我太懂你这个困扰了!TS 2.1那个时期类型系统还没像现在这么成熟,网上一堆用Babel写的React DnD示例,直接套到TS里要么类型报错要么跑不起来。下面给你一套完全适配TypeScript 2.1的完整示例,从拖拽源、放置目标到根组件的配置都给你写清楚,还附带针对TS2.1的关键注意事项:

完整TypeScript 2.1 + React DnD示例

第一步:安装兼容版本的依赖

TS2.1对新特性支持有限,必须用特定版本的React DnD才能避免类型冲突,执行以下命令安装:

npm install react-dnd@2.5.4 react-dnd-html5-backend@2.5.4 --save

1. 定义拖拽类型常量

先统一管理拖拽元素的类型标识,避免字符串硬编码带来的错误:

const ItemTypes = {
  BOX: 'box' as string
};

这里加as string是因为TS2.1的类型推断不够完善,需要明确指定类型避免歧义。

2. 拖拽源组件(DraggableBox)

实现可拖拽的盒子组件,使用DragSource高阶包装,全程严格遵循TS2.1的类型规范:

import * as React from 'react';
import { DragSource, DragSourceConnector, DragSourceMonitor } from 'react-dnd';

// 拖拽源核心逻辑:开始拖拽时传递的数据
const boxSource = {
  beginDrag(props: { name: string }) {
    return { name: props.name };
  }
};

// 收集拖拽状态与连接方法,传递给组件Props
function collect(connect: DragSourceConnector, monitor: DragSourceMonitor) {
  return {
    connectDragSource: connect.dragSource(),
    isDragging: monitor.isDragging()
  };
}

// 明确组件Props的类型定义(TS2.1必须显式声明)
type DraggableBoxProps = {
  name: string;
  connectDragSource: (node: React.ReactNode) => React.ReactNode;
  isDragging: boolean;
};

class DraggableBox extends React.Component<DraggableBoxProps, {}> {
  render() {
    const { connectDragSource, isDragging, name } = this.props;
    // 用connectDragSource包裹可拖拽元素
    return connectDragSource(
      <div
        style={{
          opacity: isDragging ? 0.5 : 1,
          padding: '20px',
          border: '1px solid gray',
          margin: '10px',
          cursor: 'move'
        }}
      >
        {name}
      </div>
    );
  }
}

// 包装成拖拽源组件
export default DragSource(ItemTypes.BOX, boxSource, collect)(DraggableBox);

3. 放置目标组件(DropZone)

实现接收拖拽元素的区域,使用DropTarget高阶包装:

import * as React from 'react';
import { DropTarget, DropTargetConnector, DropTargetMonitor } from 'react-dnd';

// 放置目标核心逻辑:处理元素放下后的行为
const zoneTarget = {
  drop(monitor: DropTargetMonitor) {
    const item = monitor.getItem();
    alert(`你放下了:${item.name}`);
  }
};

// 收集放置状态与连接方法,传递给组件Props
function collect(connect: DropTargetConnector, monitor: DropTargetMonitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    isOver: monitor.isOver()
  };
}

// 明确组件Props的类型定义
type DropZoneProps = {
  connectDropTarget: (node: React.ReactNode) => React.ReactNode;
  isOver: boolean;
};

class DropZone extends React.Component<DropZoneProps, {}> {
  render() {
    const { connectDropTarget, isOver } = this.props;
    // 用connectDropTarget包裹可放置区域
    return connectDropTarget(
      <div
        style={{
          padding: '40px',
          border: isOver ? '2px dashed blue' : '2px dashed gray',
          margin: '20px'
        }}
      >
        {isOver ? '松开放下盒子' : '拖拽盒子到这里'}
      </div>
    );
  }
}

// 包装成放置目标组件
export default DropTarget(ItemTypes.BOX, zoneTarget, collect)(DropZone);

4. 根组件(App)

用DragDropContext包裹根组件,启用HTML5拖拽后端:

import * as React from 'react';
import { render } from 'react-dom';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import DraggableBox from './DraggableBox';
import DropZone from './DropZone';

class App extends React.Component<{}, {}> {
  render() {
    return (
      <div>
        <h2>React DnD + TypeScript 2.1 示例</h2>
        <DraggableBox name="盒子1" />
        <DraggableBox name="盒子2" />
        <DropZone />
      </div>
    );
  }
}

// 用HTML5后端包装根组件
export default DragDropContext(HTML5Backend)(App);

// 渲染到页面
render(<App />, document.getElementById('root'));

针对TS2.1的关键补充:手动添加类型声明

TS2.1时期还没有官方的@types/react-dnd,所以需要在项目根目录创建react-dnd.d.ts文件,补充基础类型声明避免报错:

declare module 'react-dnd' {
  import * as React from 'react';

  export type DragSourceConnector = {
    dragSource: (options?: any) => (node: React.ReactNode) => React.ReactNode;
  };

  export type DragSourceMonitor = {
    isDragging: () => boolean;
    getItem: () => any;
  };

  export type DropTargetConnector = {
    dropTarget: (options?: any) => (node: React.ReactNode) => React.ReactNode;
  };

  export type DropTargetMonitor = {
    isOver: () => boolean;
    getItem: () => any;
  };

  export function DragSource(
    type: string,
    source: any,
    collect: (connect: DragSourceConnector, monitor: DragSourceMonitor) => any
  ): (Component: React.ComponentClass<any>) => React.ComponentClass<any>;

  export function DropTarget(
    type: string,
    target: any,
    collect: (connect: DropTargetConnector, monitor: DragSourceMonitor) => any
  ): (Component: React.ComponentClass<any>) => React.ComponentClass<any>;

  export function DragDropContext(backend: any): (Component: React.ComponentClass<any>) => React.ComponentClass<any>;
}

declare module 'react-dnd-html5-backend' {
  const backend: any;
  export default backend;
}

内容的提问来源于stack exchange,提问作者javaallone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:34:05