reactjs - Určenie typu udalosti onClick s Typescriptom a React.Konva
Snažím sa zbaviť chyby tslint Type declaration of 'any' loses type-safety., ale mám problém zistiť, aký by mal byť správny typ pre Event.
Pracujem na kurze Lynda „Building and Deploying a Full-Stack React Application“ a snažím sa ho previesť do Typescriptu.
Tu sú konkrétne riadky, ktoré spôsobujú problém:
onClick={(event: any) => {
makeMove(ownMark, event.target.index)
}}
Skúšal som deklarovať udalosť ako niekoľko rôznych typov, ako napríklad React.MouseEvent<HTMLElement>, plus niekoľko ďalších podtypov na HTMLElement, ale bez úspechu, pretože target.index nie je vlastnosťou žiadneho typu, ktorý ma napadol. Z inspektora vidím, že currentTarget je Konva.Text a index je nastavený na 0, ale nie som si istý, či mi to pomôže, pretože nemôžem nastaviť typ na Konva.Text, čo by dávalo zmysel pre mňa, ale ani to nefunguje.
Tu je moja kompletná funkčná komponenta 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>
)
}
Tu sú moje závislosti v 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"
},
Myslím, že index pridáva trieda Konva Layer, ale som dosť nový v celom React ekosystéme, takže sa stále snažím pochopiť všetko.
AKTUALIZÁCIA :
Podarilo sa mi použiť návrh na zlúčenie deklarácií od Tylera Sebastiona na definovanie indexu na terči, ktorý umlčal tslint. Nie som si však istý, či je to najlepší prístup, pretože mi to príde trochu krehké.
Tu je dodatočný kód rozhrania a aktualizovaná udalosť 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)
}}
/>
)
Odpoveď č. 1
Skutočný typ udalosti závisí od triedy HTML prvku, ktorý udalosť spôsobil.
Ak ide o <input type=button .., bude to event: React.MouseEvent<HTMLInputElement>. Ak ide o <button .., bude to event: React.MouseEvent<HTMLButtonElement>. Ak je to nejaký odkaz alebo kotva (napríklad Floating Action Buttons), môže to byť event: React.MouseEvent<HTMLAnchorElement>.
Avšak všetky tieto sú podtriedy HTMLElement
Takže vo väčšine prípadov, ak vám nezáleží na konkrétnej podtriede elementu generujúceho udalosť a jednoducho chcete získať .ownerDocument z neho alebo nejaký iný všeobecný atribút z základného HTMLElement, môžete použiť:
onClick={(event: React.MouseEvent<HTMLElement>) => {
// say you are served inside the iframe and want to grab right
// parent document reference:
(event.target as HTMLElement).ownerDocument || document).blah
}}
Avšak často potrebujete hodnotu zo špecifického atribútu podtriedy HTMLElement, napríklad .value z input elementu, potom v podstate musíte špecifikovať túto triedu elementu ako T pre MouseEvent:
onClick={(event: React.MouseEvent<HTMLInputElement>) => {
// .value attribute exists only on HTMLInputElement,
// not on parent class HTMLElement
console.log('Input field value: ' + (event.target as HTMLInputElement).value)
}}
Ak nie je jasné, aká konkrétne podtrieda HTMLElement bude nakoniec (napríklad ak máte knižnicu widgetov od tretej strany), vykreslite ju a pozrite sa, či sa vykreslí ako vstupný prvok/kotva s udalosťou onClick, alebo použite odporúčanie sniffingu od @Callum-Anderson nižšie.
Odpoveď č. 2
React.MouseEvent funguje pre mňa:
private onClick = (e: React.MouseEvent<HTMLInputElement>) => {
let button = e.target as HTMLInputElement;
}
Odpoveď č. 3
Ako som uviedol vo svojej aktualizácii vyššie, potenciálnym riešením by bolo použiť zlučovanie deklarácií, ako navrhol @Tyler-sebastion. Podarilo sa mi definovať dve ďalšie rozhrania a pridať vlastnosť index na EventTarget týmto spôsobom.
interface KonvaTextEventTarget extends EventTarget {
index: number
}
interface KonvaMouseEvent extends React.MouseEvent<HTMLElement> {
target: KonvaTextEventTarget
}
Potom môžem udalosť deklarovať ako KonvaMouseEvent vo svojej funkcii onclick MouseEventHandler.
onClick={(event: KonvaMouseEvent) => {
makeMove(ownMark, event.target.index)
}}
Stále si nie som úplne istý, či je toto ten najlepší prístup, pretože to pôsobí trochu neohrabane a nadmerne rozvláčne len aby som sa prepracoval cez chybu tslint.
Odpoveď č. 4
Môžeš to urobiť takto
onClick: React.MouseEventHandler<HtmlInputElement> = (e) => {
const button = e.target as HTML
}
Odpoveď č. 5
Myslím, že správny typ je
event:React.MouseEvent<HTMLButtonElement, MouseEvent>
Odpoveď č. 6
Mali by ste používať event.currentTarget. React odráža rozdiel medzi currentTarget (prvok, ku ktorému je udalosť pripojená) a target (prvok, na ktorom udalosť aktuálne prebieha). Keďže ide o udalosť myši, typovo môžu byť tieto dva rozdielne, aj keď to pri kliknutí nedáva zmysel.
https://github.com/facebook/react/issues/5733 https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
