使用Typescript和React.Konva指定onClick事件类型

时间:2017-07-13 19:55:16

标签: reactjs typescript konvajs

我试图摆脱我的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 Konva Event target Index

这是我完整的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 Layer类添加的,但我对整个反应生态系统都是新手,所以仍然试图将我的大脑包裹起来。

UPDATE:

我能够使用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)
    }}
  />
)

6 个答案:

答案 0 :(得分:34)

如果没有一些黑客的解决方法,你可能会失去运气

你可以尝试

onClick={(event: React.MouseEvent<HTMLElement>) => {
 makeMove(ownMark, (event.target as any).index)
}}

我不确定你的短信有多严格 - 这可能会把它关闭一点

我玩了一会儿,但无法弄清楚,但你也可以考虑编写自己的增强定义:https://www.typescriptlang.org/docs/handbook/declaration-merging.html

编辑:请使用this reply中的实现解决此问题的正确方法(并且还要投票给他,而你就是这样)。

答案 1 :(得分:8)

正如我在上面的更新中所述,可能的解决方案是使用@ 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%,因为它感觉有点Kludgy并且过于冗长只是为了克服tslint错误。

答案 2 :(得分:6)

React.MouseEvent适合我:

private onClick = (e: React.MouseEvent<HTMLInputElement>) => {
  let button = e.target as HTMLInputElement;
}

答案 3 :(得分:2)

来自ReactKonvaCore.d.ts文件:

onClick?(evt: Konva.KonvaEventObject<MouseEvent>): void;

因此,我想说您的事件类型为Konva.KonvaEventObject<MouseEvent>

答案 4 :(得分:2)

你可以这样做

   onClick: React.MouseEventHandler<HtmlInputElement> = (e) => {
     const button = e.target as HTML
}

答案 5 :(得分:0)

您应该使用event.currentTarget。 React正在镜像currentTarget(事件附加到的元素)和target(事件当前发生在的元素)之间的差异。由于这是鼠标事件,因此即使在单击时没有意义,二者在类型上也可能有所不同。

https://github.com/facebook/react/issues/5733 https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget