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

Posted

技术标签:

【中文标题】使用 Typescript 和 React.Konva 指定 onClick 事件类型【英文标题】:Specifying onClick event type with Typescript and React.Konva 【发布时间】:2017-12-18 18:45:24 【问题描述】:

我正在尝试摆脱我的 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 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)
    
  />
)

【问题讨论】:

【参考方案1】:

如果没有一些 hack-y 变通办法,你可能不走运

你可以试试

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

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

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

编辑:请使用this reply 中的实现,这是解决此问题的正确方法(同时也支持他,当你在它的时候)。

【讨论】:

感谢您的想法。我打算尝试投射目标,但从未尝试过。我肯定会试一试,尽管这绝对是一种解决方法。我肯定会阅读声明合并,因为我以前没有见过。 Lambda 在 JSX 属性中被禁止使用,因为它们会影响渲染性能 @AlexeySh。他们气馁,是的。我从 OP 的代码中复制过来的。 这可以简单地移动到 React.useCallback 以节省 lambda 为什么您的编辑回复是正确的?你的方法有什么问题?【参考方案2】:

React.MouseEvent 对我有用:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

你可以这样做

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

【讨论】:

您能否详细说明为什么这可以解决问题?【参考方案6】:

取自 ReactKonvaCore.d.ts 文件:

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

所以,我会说你的事件类型是Konva.KonvaEventObject&lt;MouseEvent&gt;

【讨论】:

ReactKonvaCore.d.ts => 你能发布直接链接吗 @Nelles 快速搜索出现github.com/konvajs/react-konva/blob/master/ReactKonvaCore.d.ts

以上是关于使用 Typescript 和 React.Konva 指定 onClick 事件类型的主要内容,如果未能解决你的问题,请参考以下文章

typescript 使用TypeScript和MongoDb的Mongoose示例

TypeScript 和 JavaScript 的区别

TypeScript 和 JavaScript 的区别

如何使用 TypeScript 和 Sequelize

交替使用 TypeScript 和 Nim 的一些感想

使用源映射和 webpack 调试 typescript