使用 Typescript 和 React.Konva 指定 onClick 事件类型
Specifying onClick event type with Typescript and React.Konva
我正在尝试消除我的 tslint 错误 Type declaration of 'any' loses type-safety.
但我正在努力找出事件的正确类型。
我正在尝试将 Lynda“Building and Deploying a Full-Stack React Application”转换为 Typescript。
以下是导致问题的具体线路:
onClick={(event: any) => {
makeMove(ownMark, event.target.index)
}}
我尝试将事件声明为几种不同的类型,例如 React.MouseEvent<HTMLElement>
,以及 HTMLElement 上的一些其他子类型,但没有成功,因为 target.index 不是 属性 在我能想到的任何类型上。我可以从检查器中看到 currentTarget 是 Konva.Text 并且索引设置为 0
但不确定这对我有帮助,因为我无法将类型设置为 Konva.Text
,这将使对我来说有意义,但这也不起作用。
这是我完整的 React 功能组件:
export const Squares = ({units, coordinates, gameState, win, gameOver, yourTurn, ownMark, move}: SquaresProps) => {
let squares = coordinates.map( (position: number, index: number) => {
let makeMove = move
let mark = gameState[index] !== 'z' ? gameState[index] : false
let fill = 'black'
// when someone wins you want the square to turn green
if (win && win.includes(index)) {
fill = 'lightGreen'
}
if (gameOver || !yourTurn || mark) {
makeMove = () => console.log('nope!')
}
return (
<Text
key={index}
x={position[0]}
y={position[1]}
fontSize={units}
width={units}
text={mark}
fill={fill}
fontFamily={'Helvetica'}
aligh={'center'}
onClick={(event: any) => {
makeMove(ownMark, event.target.index)
}}
/>
)
})
return (
<Layer>
{squares}
</Layer>
)
}
这是我的 package.json
依赖项:
"dependencies": {
"konva": "^1.6.3",
"material-ui": "^0.18.4",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-konva": "^1.1.3",
"react-router": "~3.0.0",
"react-tap-event-plugin": "^2.0.1",
"styled-components": "^2.1.0"
},
我 认为 索引是由 Konva 层添加的 class 但我对整个 React 生态系统还很陌生,所以仍在努力思考这一切。
更新:
我能够使用 Tyler Sebastion 的声明合并建议来定义目标上的索引,从而使 tslint 静音。我不确定这是最好的方法,因为它对我来说有点脆弱。
这是额外的接口代码和更新的 onclick 事件:
interface KonvaTextEventTarget extends EventTarget {
index: number
}
interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
target: KonvaTextEventTarget
}
...
return (
<Text
key={index}
x={position[0]}
y={position[1]}
fontSize={units}
width={units}
text={mark}
fill={fill}
fontFamily={'Helvetica'}
aligh={'center'}
onClick={(event: KonvaMouseEvent) => {
makeMove(ownMark, event.target.index)
}}
/>
)
如果没有一些 hack-y 解决方法,您可能会倒霉
你可以试试
onClick={(event: React.MouseEvent<HTMLElement>) => {
makeMove(ownMark, (event.target as any).index)
}}
我不确定你的 linter 有多严格 - 这可能会让它闭嘴一点
我玩了一会儿,没弄明白,但你也可以考虑编写自己的扩充定义:https://www.typescriptlang.org/docs/handbook/declaration-merging.html
编辑:请使用 中的实现,它是 解决此问题的正确方法 (同时也为他点赞)。
正如我在上面的更新中所发布的,一个潜在的解决方案是使用@Tyler-sebastion 建议的声明合并。我能够定义两个额外的接口并以这种方式在 EventTarget
上添加索引 属性。
interface KonvaTextEventTarget extends EventTarget {
index: number
}
interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
target: KonvaTextEventTarget
}
然后我可以在我的 onclick MouseEventHandler 函数中将事件声明为 KonvaMouseEvent
。
onClick={(event: KonvaMouseEvent) => {
makeMove(ownMark, event.target.index)
}}
如果这是最好的方法,我仍然不是 100%,因为它感觉有点笨拙并且过于冗长只是为了克服 tslint 错误。
React.MouseEvent 适合我:
private onClick = (e: React.MouseEvent<HTMLInputElement>) => {
let button = e.target as HTMLInputElement;
}
您应该使用 event.currentTarget。 React 反映了 currentTarget(事件附加到的元素)和 target(事件当前正在发生的元素)之间的区别。由于这是一个鼠标事件,因此两者在类型上可能不同,即使点击没有意义。
https://github.com/facebook/react/issues/5733
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
取自 ReactKonvaCore.d.ts 文件:
onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
那么,我会说你的活动类型是 Konva.KonvaEventObject<MouseEvent>
你可以这样做
onClick: React.MouseEventHandler<HtmlInputElement> = (e) => {
const button = e.target as HTML
}
我正在尝试消除我的 tslint 错误 Type declaration of 'any' loses type-safety.
但我正在努力找出事件的正确类型。
我正在尝试将 Lynda“Building and Deploying a Full-Stack React Application”转换为 Typescript。
以下是导致问题的具体线路:
onClick={(event: any) => {
makeMove(ownMark, event.target.index)
}}
我尝试将事件声明为几种不同的类型,例如 React.MouseEvent<HTMLElement>
,以及 HTMLElement 上的一些其他子类型,但没有成功,因为 target.index 不是 属性 在我能想到的任何类型上。我可以从检查器中看到 currentTarget 是 Konva.Text 并且索引设置为 0
但不确定这对我有帮助,因为我无法将类型设置为 Konva.Text
,这将使对我来说有意义,但这也不起作用。
这是我完整的 React 功能组件:
export const Squares = ({units, coordinates, gameState, win, gameOver, yourTurn, ownMark, move}: SquaresProps) => {
let squares = coordinates.map( (position: number, index: number) => {
let makeMove = move
let mark = gameState[index] !== 'z' ? gameState[index] : false
let fill = 'black'
// when someone wins you want the square to turn green
if (win && win.includes(index)) {
fill = 'lightGreen'
}
if (gameOver || !yourTurn || mark) {
makeMove = () => console.log('nope!')
}
return (
<Text
key={index}
x={position[0]}
y={position[1]}
fontSize={units}
width={units}
text={mark}
fill={fill}
fontFamily={'Helvetica'}
aligh={'center'}
onClick={(event: any) => {
makeMove(ownMark, event.target.index)
}}
/>
)
})
return (
<Layer>
{squares}
</Layer>
)
}
这是我的 package.json
依赖项:
"dependencies": {
"konva": "^1.6.3",
"material-ui": "^0.18.4",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-konva": "^1.1.3",
"react-router": "~3.0.0",
"react-tap-event-plugin": "^2.0.1",
"styled-components": "^2.1.0"
},
我 认为 索引是由 Konva 层添加的 class 但我对整个 React 生态系统还很陌生,所以仍在努力思考这一切。
更新:
我能够使用 Tyler Sebastion 的声明合并建议来定义目标上的索引,从而使 tslint 静音。我不确定这是最好的方法,因为它对我来说有点脆弱。
这是额外的接口代码和更新的 onclick 事件:
interface KonvaTextEventTarget extends EventTarget {
index: number
}
interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
target: KonvaTextEventTarget
}
...
return (
<Text
key={index}
x={position[0]}
y={position[1]}
fontSize={units}
width={units}
text={mark}
fill={fill}
fontFamily={'Helvetica'}
aligh={'center'}
onClick={(event: KonvaMouseEvent) => {
makeMove(ownMark, event.target.index)
}}
/>
)
如果没有一些 hack-y 解决方法,您可能会倒霉
你可以试试
onClick={(event: React.MouseEvent<HTMLElement>) => {
makeMove(ownMark, (event.target as any).index)
}}
我不确定你的 linter 有多严格 - 这可能会让它闭嘴一点
我玩了一会儿,没弄明白,但你也可以考虑编写自己的扩充定义:https://www.typescriptlang.org/docs/handbook/declaration-merging.html
编辑:请使用
正如我在上面的更新中所发布的,一个潜在的解决方案是使用@Tyler-sebastion 建议的声明合并。我能够定义两个额外的接口并以这种方式在 EventTarget
上添加索引 属性。
interface KonvaTextEventTarget extends EventTarget {
index: number
}
interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
target: KonvaTextEventTarget
}
然后我可以在我的 onclick MouseEventHandler 函数中将事件声明为 KonvaMouseEvent
。
onClick={(event: KonvaMouseEvent) => {
makeMove(ownMark, event.target.index)
}}
如果这是最好的方法,我仍然不是 100%,因为它感觉有点笨拙并且过于冗长只是为了克服 tslint 错误。
React.MouseEvent 适合我:
private onClick = (e: React.MouseEvent<HTMLInputElement>) => {
let button = e.target as HTMLInputElement;
}
您应该使用 event.currentTarget。 React 反映了 currentTarget(事件附加到的元素)和 target(事件当前正在发生的元素)之间的区别。由于这是一个鼠标事件,因此两者在类型上可能不同,即使点击没有意义。
https://github.com/facebook/react/issues/5733 https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
取自 ReactKonvaCore.d.ts 文件:
onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;
那么,我会说你的活动类型是 Konva.KonvaEventObject<MouseEvent>
你可以这样做
onClick: React.MouseEventHandler<HtmlInputElement> = (e) => {
const button = e.target as HTML
}