Указание типа события onClick с помощью Typescript и React.Konva

Я пытаюсь избавиться от ошибки tslint Type declaration of 'any' loses type-safety., но мне трудно понять, какой тип будет правильным для события.

Я работаю через Lynda "Создание и развертывание приложения Full-Stack React" при попытке преобразовать его в Typescript.

Вот конкретные строки, вызывающие проблему:

onClick={(event: any) => {
 makeMove(ownMark, event.target.index)
}}

Я попытался объявить событие как несколько разных типов, например React.MouseEvent<HTMLElement>, плюс несколько других подтипов на HTMLElement, но безуспешно, поскольку target.index не является свойством ни для одного типа, который я могу придумать. Я вижу из инспектора, что currentTarget - это Konva.Text, а индекс установлен на 0, но не уверен, что это помогает мне, поскольку я не могу установить тип на Konva.Text, что было бы для меня разумным, но это не работает или.

Индекс целей события React Konva

Вот мой полный функциональный компонент 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, поэтому все еще пытаюсь осмыслить все это.

ОБНОВИТЬ:

Я смог использовать предложение слияния деклараций Тайлера Себастиона, чтобы определить индекс на цели, который отключил 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)
    }}
  />
)

person Justin Levi Winter    schedule 13.07.2017    source источник


Ответы (6)


Вам, вероятно, не повезло без каких-либо хакерских обходных путей

Вы могли бы попробовать

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

Я не уверен, насколько строг ваш линтер - это может немного заткнуть его

Я немного поигрался с этим и не смог понять, но вы также можете попробовать написать свои собственные расширенные определения: https://www.typescriptlang.org/docs/handbook/declaration-merging.html

изменить: используйте реализацию в этом ответе, это правильный способ решить эту проблему ( а также проголосуйте за него, пока вы на нем).

person Tyler Sebastian    schedule 13.07.2017
comment
Спасибо за идею. Я собирался попробовать бросить цель, но так и не успел. Я обязательно сделаю это, хотя это определенно кажется временным решением. Я обязательно прочитаю о слиянии деклараций, потому что я этого раньше не видел. - person Justin Levi Winter; 14.07.2017
comment
Лямбда-выражения запрещены в атрибутах JSX из-за их влияния на производительность рендеринга. - person Alexey Sh.; 10.08.2018
comment
@AlexeySh. они разочарованы, да. Я скопировал из кода OP. - person Tyler Sebastian; 25.09.2018
comment
Это можно тривиально переместить в React.useCallback, чтобы сэкономить на лямбде. - person Patrick; 13.09.2019

React.MouseEvent у меня работает:

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

Как было опубликовано в моем обновлении выше, потенциальным решением было бы использовать слияние деклараций, как это было предложено @ Tyler-sebastion. Таким образом я смог определить два дополнительных интерфейса и добавить свойство index для EventTarget.

interface KonvaTextEventTarget extends EventTarget {
  index: number
}

interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
  target: KonvaTextEventTarget
}

Затем я могу объявить событие как KonvaMouseEvent в моей функции onclick MouseEventHandler.

onClick={(event: KonvaMouseEvent) => {
          makeMove(ownMark, event.target.index)
}}

Я все еще не на 100%, если это лучший подход, поскольку он кажется немного беспорядочным и слишком многословным, просто чтобы обойти ошибку tslint.

person Justin Levi Winter    schedule 14.07.2017

Вы должны использовать event.currentTarget. React отражает разницу между currentTarget (элементом, к которому привязано событие) и target (элементом, на котором в настоящее время происходит событие). Поскольку это событие мыши, по типу они могут отличаться, даже если щелчок не имеет смысла.

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

person insomniac2846    schedule 11.12.2019

Взято из файла ReactKonvaCore.d.ts:

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

Итак, я бы сказал, что ваше событие Konva.KonvaEventObject<MouseEvent>

person Roland Zwaga    schedule 19.03.2020
comment
ReactKonvaCore.d.ts = ›можешь разместить прямую ссылку - person Nelles; 20.03.2020
comment
@Nelles Быстрый поиск появился github.com/konvajs/react- konva / blob / master / ReactKonvaCore.d.ts - person Digital Deception; 20.03.2020

Вы можете сделать это

   onClick: React.MouseEventHandler<HtmlInputElement> = (e) => {
     const button = e.target as HTML
}
person Ranjan Kumar    schedule 10.06.2021
comment
Не могли бы вы подробнее объяснить, почему это должно решить проблему? - person XouDo; 10.06.2021