John Miller
John Miller

Reputation: 407

Typescript and React: What is the proper type for an event handler that uses destructuring?

I'm having problems with the strictness of Typescript when using event handlers with React. Specifically, I am unable to use object destructuring with my handleClick() function that goes on the onClick={handleClick} attribute.

This is the unclean version, and it is the only one typescript acceps without complaining:

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    const target: Element = event.target as Element
    // ...other code goes here
}

This is the clean version, and typescript throws errors:

const handleClick = ({ target }: { target: Element }) => {
    // ...other code goes here
}

The second block of code (the unclean version) causes Typescript to throw an error. When I hover over the onClick={handleClick} attribute, this frutratingly cryptic error is displayed:

Type '({ target }: { target: Element; }) => void' is not assignable to type 'MouseEventHandler'. Types of parameters '__0' and 'event' are incompatible. Type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to type '{ target: Element; }'. Types of property 'target' are incompatible. Type 'EventTarget' is missing the following properties from type 'Element': attributes, classList, className, clientHeight, and 120 more.ts(2322) index.d.ts(1457, 9): The expected type comes from property 'onClick' which is declared here on type 'DetailedHTMLProps<ButtonHTMLAttributes, HTMLButtonElement>'

Does anybody have a solution to this? I am stumped.

Thank you in advance.

Upvotes: 4

Views: 12302

Answers (1)

Oblosys
Oblosys

Reputation: 15106

You can just use the same type React.MouseEvent<HTMLButtonElement> for the destructured parameter. This will infer the correct type for target. You'll probably want to use currentTarget though, which is the element the handler was attached to, rather than target, which is the element the event occurred on. For a button they will be the same, but TypeScript can only infer the actual element type for currentTarget.

import * as React from "react";

const handleClick = ({ target, currentTarget }: React.MouseEvent<HTMLButtonElement>) => {
    // target: EventTarget
    // currentTarget: EventTarget & HTMLButtonElement

    // ...other code goes here
}

const elt = <button onClick={handleClick} />

Playground Link

Upvotes: 8

Related Questions