打字稿中的简单 react-dnd 列表在尝试 运行 示例时给我编译错误
Simple react-dnd list in typescript is giving me compilation errors when trying to run the example
我正在尝试让这个漂亮的 react-dnd 示例正常工作,但我目前遇到了一些错误:
import * as React from 'react';
import {
DragDropContext,
Draggable,
Droppable,
DroppableProvided,
DraggableLocation,
DropResult,
DroppableStateSnapshot, DraggableProvided, DraggableStateSnapshot
} from 'react-beautiful-dnd';
import {Flex} from 'grid-styled'
import './App.css';
interface Item {
id: string;
content: string;
}
interface IAppState {
items: Item[];
selected: Item[];
}
interface IMoveResult {
droppable: Item[];
droppable2: Item[];
}
const getItems = (count: number, offset:number = 0): Item[] => {
return Array
.from({length: count}, (v, k) => k)
.map(k => ({
content: `item ${k + offset}`,
id: `item-${k + offset}`
}));
};
const reorder = (list: Item[], startIndex: number, endIndex: number):Item[] => {
const result = [...list];
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
/**
* Moves an item from one list to another list.
*/
const move = (source: Item[], destination: Item[], droppableSource:DraggableLocation, droppableDestination:DraggableLocation):IMoveResult | any => {
const sourceClone = [...source];
const destClone = [...destination];
const [removed] = sourceClone.splice(droppableSource.index, 1);
destClone.splice(droppableDestination.index, 0, removed);
const result = {};
result[droppableSource.droppableId] = sourceClone;
result[droppableDestination.droppableId] = destClone;
return result;
};
const grid:number = 8;
const getItemStyle = (draggableStyle: any, isDragging: boolean):{} => ({
userSelect: 'none',
padding: 2*grid,
margin: `0 0 ${grid}px 0`,
background: isDragging ? 'lightgreen' : 'grey',
...draggableStyle
});
const getListStyle = (isDraggingOver: boolean):{} => ({
background: isDraggingOver ? 'lightblue' : 'lightgrey',
padding: grid,
width: 300,
minHeight: 400
});
export default class App extends React.Component<{}, IAppState> {
public id2List = {
droppable: 'items',
droppable2: 'selected'
};
constructor(props:any) {
super(props);
this.state = {
items: getItems(10, 0),
selected: getItems(5, 10)
};
this.onDragEnd = this.onDragEnd.bind(this);
this.getList = this.getList.bind(this);
}
public getList (id:string):Item[] {
return this.state[this.id2List[id]];
}
public onDragEnd(result: DropResult):void {
const { source, destination } = result;
if (!destination) {
return;
}
if (source.droppableId === destination.droppableId) {
const items = reorder(
this.getList(source.droppableId),
source.index,
destination.index
);
let state:IAppState = {...this.state};
if (source.droppableId === "droppable2") {
state = { ...this.state, selected: items };
} else if (source.droppableId === "droppable") {
state = {...this.state, items}
}
this.setState(state);
} else {
const resultFromMove:IMoveResult = move(
this.getList(source.droppableId),
this.getList(destination.droppableId),
source,
destination
);
this.setState({
items: resultFromMove.droppable,
selected: resultFromMove.droppable2
});
}
}
public render() {
return (
<DragDropContext onDragEnd={this.onDragEnd}>
<Flex justifyContent={"space-between"}>
<Flex flexDirection="column">
<Droppable droppableId="droppable">
{(provided:DroppableProvided, snapshot:DroppableStateSnapshot) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
style={getListStyle(snapshot.isDraggingOver)}
>
{this.state.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(providedDraggable:DraggableProvided, snapshotDraggable:DraggableStateSnapshot) => (
<div>
<div
ref={providedDraggable.innerRef}
{...providedDraggable.draggableProps}
{...providedDraggable.dragHandleProps}
style={getItemStyle(
providedDraggable.draggableProps.style,
snapshotDraggable.isDragging
)}
>
{item.content}
</div>
{providedDraggable.placeholder}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</Flex>
<Droppable droppableId="droppable2">
{(providedDroppable2:DroppableProvided, snapshotDroppable2:DroppableStateSnapshot) => (
<div
ref={providedDroppable2.innerRef}
style={getListStyle(snapshotDroppable2.isDraggingOver)}>
{this.state.selected.map((item, index) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(providedDraggable2:DraggableProvided, snapshotDraggable2:DraggableStateSnapshot) => (
<div>
<div
ref={providedDraggable2.innerRef}
{...providedDraggable2.draggableProps}
{...providedDraggable2.dragHandleProps}
style={getItemStyle(
providedDraggable2.draggableProps.style,
snapshotDraggable2.isDragging
)}>
{item.content}
</div>
{providedDraggable2.placeholder}
</div>
)}
</Draggable>
))}
{providedDroppable2.placeholder}
</div>
)}
</Droppable>
</Flex>
</DragDropContext>
);
}
}
目前我在尝试 运行 这个例子时看到了 2 个错误:
错误#1
元素隐式具有 'any' 类型,因为类型 'string' 的表达式不能用于索引类型“{}”。
在类型“{}”上找不到参数类型为 'string' 的索引签名。 TS7053
result[droppableSource.droppableId] = sourceClone;
错误#2
元素隐式具有 'any' 类型,因为类型 'any' 的表达式不能用于索引类型 'Readonly'。 TS7053
public getList(id: string): 项目[] {
99 | return this.state[this.id2List[id]];
| ^
100 | }
这是我的依赖项:
"dependencies": {
"@reduxjs/toolkit": "^1.5.1",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.0",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.7",
"@types/react-router-dom": "^5.3.2",
"react": "^17.0.2",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-redux": "^7.2.0",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",
"typescript": "~4.1.5"
},
如果您使用 TypeScript,则必须为您的变量提供类型。否则类型检查根本没有帮助。
const result : { [key:string]:Item[]; } = {};
应该解决第一个问题。我没有尝试代码,如果它不起作用我会更正它。
这个构造也是如此:
public id2List = {
droppable: 'items',
droppable2: 'selected'
}; // <-- what is the type here?
我猜应该是
public id2List = {
droppable: 'items',
droppable2: 'selected'
} as { [key:string]: keyof IAppState; };
要了解有关这些类型的更多信息,您可以查看 TypeScript 中的 Index Signatures 概念。此外,如果您可以避免它们并在类型中使用适当的属性名称,那么最好这样做,因为缩小类型可以使您的代码更不容易出错。
因为 App 组件是参数化的 class,它得到 IAppState
作为 this.state
的类型。要将 id2List
值绑定到 IAppState
中的 属性 名称,使用 keyof 运算符。
值得一提的是,如果您不能或不想找出正确的类型,您也可以将 'any' 明确声明为一种类型。 IE。 const result: any = {};
可能仍然可以被编译器接受,具体取决于设置。但它也无视任何首先使用 TS 的理由。
我正在尝试让这个漂亮的 react-dnd 示例正常工作,但我目前遇到了一些错误:
import * as React from 'react';
import {
DragDropContext,
Draggable,
Droppable,
DroppableProvided,
DraggableLocation,
DropResult,
DroppableStateSnapshot, DraggableProvided, DraggableStateSnapshot
} from 'react-beautiful-dnd';
import {Flex} from 'grid-styled'
import './App.css';
interface Item {
id: string;
content: string;
}
interface IAppState {
items: Item[];
selected: Item[];
}
interface IMoveResult {
droppable: Item[];
droppable2: Item[];
}
const getItems = (count: number, offset:number = 0): Item[] => {
return Array
.from({length: count}, (v, k) => k)
.map(k => ({
content: `item ${k + offset}`,
id: `item-${k + offset}`
}));
};
const reorder = (list: Item[], startIndex: number, endIndex: number):Item[] => {
const result = [...list];
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
/**
* Moves an item from one list to another list.
*/
const move = (source: Item[], destination: Item[], droppableSource:DraggableLocation, droppableDestination:DraggableLocation):IMoveResult | any => {
const sourceClone = [...source];
const destClone = [...destination];
const [removed] = sourceClone.splice(droppableSource.index, 1);
destClone.splice(droppableDestination.index, 0, removed);
const result = {};
result[droppableSource.droppableId] = sourceClone;
result[droppableDestination.droppableId] = destClone;
return result;
};
const grid:number = 8;
const getItemStyle = (draggableStyle: any, isDragging: boolean):{} => ({
userSelect: 'none',
padding: 2*grid,
margin: `0 0 ${grid}px 0`,
background: isDragging ? 'lightgreen' : 'grey',
...draggableStyle
});
const getListStyle = (isDraggingOver: boolean):{} => ({
background: isDraggingOver ? 'lightblue' : 'lightgrey',
padding: grid,
width: 300,
minHeight: 400
});
export default class App extends React.Component<{}, IAppState> {
public id2List = {
droppable: 'items',
droppable2: 'selected'
};
constructor(props:any) {
super(props);
this.state = {
items: getItems(10, 0),
selected: getItems(5, 10)
};
this.onDragEnd = this.onDragEnd.bind(this);
this.getList = this.getList.bind(this);
}
public getList (id:string):Item[] {
return this.state[this.id2List[id]];
}
public onDragEnd(result: DropResult):void {
const { source, destination } = result;
if (!destination) {
return;
}
if (source.droppableId === destination.droppableId) {
const items = reorder(
this.getList(source.droppableId),
source.index,
destination.index
);
let state:IAppState = {...this.state};
if (source.droppableId === "droppable2") {
state = { ...this.state, selected: items };
} else if (source.droppableId === "droppable") {
state = {...this.state, items}
}
this.setState(state);
} else {
const resultFromMove:IMoveResult = move(
this.getList(source.droppableId),
this.getList(destination.droppableId),
source,
destination
);
this.setState({
items: resultFromMove.droppable,
selected: resultFromMove.droppable2
});
}
}
public render() {
return (
<DragDropContext onDragEnd={this.onDragEnd}>
<Flex justifyContent={"space-between"}>
<Flex flexDirection="column">
<Droppable droppableId="droppable">
{(provided:DroppableProvided, snapshot:DroppableStateSnapshot) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
style={getListStyle(snapshot.isDraggingOver)}
>
{this.state.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{(providedDraggable:DraggableProvided, snapshotDraggable:DraggableStateSnapshot) => (
<div>
<div
ref={providedDraggable.innerRef}
{...providedDraggable.draggableProps}
{...providedDraggable.dragHandleProps}
style={getItemStyle(
providedDraggable.draggableProps.style,
snapshotDraggable.isDragging
)}
>
{item.content}
</div>
{providedDraggable.placeholder}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</Flex>
<Droppable droppableId="droppable2">
{(providedDroppable2:DroppableProvided, snapshotDroppable2:DroppableStateSnapshot) => (
<div
ref={providedDroppable2.innerRef}
style={getListStyle(snapshotDroppable2.isDraggingOver)}>
{this.state.selected.map((item, index) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(providedDraggable2:DraggableProvided, snapshotDraggable2:DraggableStateSnapshot) => (
<div>
<div
ref={providedDraggable2.innerRef}
{...providedDraggable2.draggableProps}
{...providedDraggable2.dragHandleProps}
style={getItemStyle(
providedDraggable2.draggableProps.style,
snapshotDraggable2.isDragging
)}>
{item.content}
</div>
{providedDraggable2.placeholder}
</div>
)}
</Draggable>
))}
{providedDroppable2.placeholder}
</div>
)}
</Droppable>
</Flex>
</DragDropContext>
);
}
}
目前我在尝试 运行 这个例子时看到了 2 个错误:
错误#1 元素隐式具有 'any' 类型,因为类型 'string' 的表达式不能用于索引类型“{}”。 在类型“{}”上找不到参数类型为 'string' 的索引签名。 TS7053
result[droppableSource.droppableId] = sourceClone;
错误#2 元素隐式具有 'any' 类型,因为类型 'any' 的表达式不能用于索引类型 'Readonly'。 TS7053
public getList(id: string): 项目[] {
99 | return this.state[this.id2List[id]]; | ^ 100 | }
这是我的依赖项:
"dependencies": {
"@reduxjs/toolkit": "^1.5.1",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/jest": "^24.0.0",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.7",
"@types/react-router-dom": "^5.3.2",
"react": "^17.0.2",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-redux": "^7.2.0",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",
"typescript": "~4.1.5"
},
如果您使用 TypeScript,则必须为您的变量提供类型。否则类型检查根本没有帮助。
const result : { [key:string]:Item[]; } = {};
应该解决第一个问题。我没有尝试代码,如果它不起作用我会更正它。
这个构造也是如此:
public id2List = {
droppable: 'items',
droppable2: 'selected'
}; // <-- what is the type here?
我猜应该是
public id2List = {
droppable: 'items',
droppable2: 'selected'
} as { [key:string]: keyof IAppState; };
要了解有关这些类型的更多信息,您可以查看 TypeScript 中的 Index Signatures 概念。此外,如果您可以避免它们并在类型中使用适当的属性名称,那么最好这样做,因为缩小类型可以使您的代码更不容易出错。
因为 App 组件是参数化的 class,它得到 IAppState
作为 this.state
的类型。要将 id2List
值绑定到 IAppState
中的 属性 名称,使用 keyof 运算符。
值得一提的是,如果您不能或不想找出正确的类型,您也可以将 'any' 明确声明为一种类型。 IE。 const result: any = {};
可能仍然可以被编译器接受,具体取决于设置。但它也无视任何首先使用 TS 的理由。