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

问题描述 投票:0回答:12

我正在尝试摆脱 tslint 错误

Type declaration of 'any' loses type-safety.
,但我正在努力找出事件的正确类型。

我正在研究 Lynda“构建和部署全栈 React 应用程序”,同时尝试将其转换为 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 Layer 类添加的,但我对整个 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)
    }}
  />
)
reactjs typescript konvajs
12个回答
215
投票

如果没有一些 hack-y 解决方法,你可能会运气不好

你可以试试

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

我不确定你的 linter 有多严格 - 这可能会让它闭嘴一点

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

编辑:请使用此回复中的实现,这是解决此问题的正确方法(并且在您这样做时也给他投票)。


41
投票

React.MouseEvent 对我有用:

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

27
投票

正如我在上面的更新中发布的,一个潜在的解决方案是使用@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 错误。


16
投票

你可以这样做

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

11
投票

您应该使用 event.currentTarget。 React 反映了 currentTarget(事件所附加的元素)和 target(事件当前正在发生的元素)之间的差异。由于这是一个鼠标事件,因此在类型上两者可能不同,即使对于单击来说没有意义。

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


11
投票

我认为正确的类型是

event:React.MouseEvent<HTMLButtonElement, MouseEvent>

7
投票

您可以使用 IDE/编辑器中的 IntelliSense(或同等功能)来确定类型。暂时将事件处理程序放置在 HTML 元素内,然后将光标悬停在该事件上。例如。

<button onClick={(event => console.log(event))}>Click me</button>

将鼠标悬停在 VSCode 中的

event
上会显示:

(parameter) event: React.MouseEvent<HTMLButtonElement, MouseEvent>

4
投票

取自 ReactKonvaCore.d.ts 文件:

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

所以,我想说您的事件类型是

Konva.KonvaEventObject<MouseEvent>


1
投票

我想你可以尝试一下。对我有用。

const handleClick = (event: SyntheticEvent) => {
    const target = event.target 
};

<Button onClick={handleClick}>Click me</button>

1
投票
const Example = () => {

      const handleSubmission = (event: React.MouseEvent<HTMLButtonElement>): void => {
          event.preventDefault()
          .....
      }

      return <button onClick={handleSubmission}>Submit</button>
}

所以解决方案是

React.MouseEvent<HTMLButtonElement>


0
投票
onClick={(event: Event) => {
    const { index } = event.target as unknown as { index: number }; 
    makeMove(ownMark, index);
}}

0
投票

此外,要使用 DOM,您可以使用 MouseEvent
对于 @typescript-eslint 来说这是正确的。示例:

const onClickEverywhere = (e: MouseEvent) => {
  e.preventDefault();
  e.stopPropagation();
  console.log(e.target);
};

useEffect(() => {
  document.body.addEventListener('click', onClickEverywhere);
  return document.body.removeEventListener('click', onClickEverywhere);
}, []);
© www.soinside.com 2019 - 2024. All rights reserved.