JDom93
JDom93

Reputation: 73

Type guarding React.KeyboardEvent to reuse event handlers

I created a search-bar-React-Component that resembles the one by Google. It should fire off a search based on the input if I either click on the 'search' icon or if I hit the enter key.

I want to reuse the same function for both the click and the keydown handler:

...
var [searchParam, setSearchParam] = useState('');

function initSearch(
    e:
      | React.MouseEvent<HTMLButtonElement>
      | React.KeyboardEvent<HTMLInputElement>
  ): void {
    if (e.type == 'click' || (e.type == 'keydown' && e.key == 'Enter')) {
      console.log(searchParam);                    /* ⬆️ this throws the error */
    }
  }
...

TypeScript keeps giving me the following error:

'Property 'key' does not exist on type 'MouseEvent<HTMLButtonElement, MouseEvent>'

I tried both of the following:

(e instance of KeyboardEvent && e.key == 'Enter') // This is always false, since e is a React.KeyboardEvent

(e instance of React.KeyboardEvent) // KeyboardEvent is not a property of React.

What is a good way to typeguard? Is there a better way to write the function?

Thank you.

Upvotes: 1

Views: 431

Answers (2)

samuellealb
samuellealb

Reputation: 15

React.Events objects have a 'nativeEvent' property which stores the native event, for which you can check.

In your code, would look like

function initSearch(
    e:
      | (React.MouseEvent<HTMLButtonElement>
      | (React.KeyboardEvent<HTMLInputElement>
  ): void {
    if (e.nativeEvent instanceof MouseEvent || e.key === 'Enter') {
      console.log(searchParam);
    }
  }

Upvotes: 0

JDom93
JDom93

Reputation: 73

Turns out using an intersection type solved the problem:

function initSearch(
    e:
      | (React.MouseEvent<HTMLButtonElement> & { type: 'click' })  /*⬅️*/
      | (React.KeyboardEvent<HTMLInputElement> & { type: 'keydown' })  /*⬅️*/
  ): void {
    if (e.type == 'click' || (e.type == 'keydown' && e.key == 'Enter')) {
      console.log(searchParam);
    }
  }

I checked the type definitions, turns out the 'type' property is only defined as 'string', not as a definite primitive value.

In case I'm missing something here (i.e. that a keydown event can somehow not include the e.type == 'keydown' property), please let me know. It feels unnecessarily hacky!

Upvotes: 1

Related Questions