Search code examples
reactjstypescriptmaterial-uireact-typescript

Which is the right type for an event passed to the onKeyPressed function in React with MaterialUI and Typescript?


In a React app, where I use Typescript and MaterialUI, I have a TextField.

I would like to get access to the input html element value when enter is pressed.

So I have the following code

  const keyPress = (e: any) => {
    if (e.key === "Enter") {
      console.log("Do login", e.target.value);
    }
  };

and somewhere in the returned React tree I have this

<TextField onKeyPress={keyPress} />

This code works, bu my problem is that I do not understand how to define the right type for the event e passed to the function keyPressed.

According to what VSCode intellisense is suggesting when I hover over onKeyPress prop, I understand I should use KeyboardEvent<HTMLDivElement>, but the problem is that then I get an error which says Type 'KeyboardEvent' is not generic.

What I am doing wrong?

By the way, everything works fine if I give the event the type e: { key: string; target: any }, but still it is interesting to understand what I am doing wrong when I try to follow the right way.

UPDATE

After some more research, it seems that the event passed to keyPressed function is of type KeyboardEvent and that its target property is of type EventTarget.

Looking at the definition of EventTarget in global.d.ts in React package, then I see that it is the empty interface.

In the comments of global.d.ts I read also that "Warning: all of these interfaces are empty. If you want type definitions for various properties (such as HTMLInputElement.prototype.value), you need to add --lib DOM (via command line or tsconfig.json).". But my tsconfig.json actually contains DOM in the libraries (the property is "lib": ["dom", "dom.iterable", "esnext"],).

Again, I can make things work, but I would like to understand how to get a clean type for that event.


Solution

  • You can define typing for onKeyPress handler i.e. keyPress as:

    import { KeyboardEvent, EventHandler } from 'react'
    
    const keyPress: EventHandler<KeyboardEvent<HTMLInputElement>> = (e) => {
      if (e.key === 'Enter') {
        console.log('Do login', (e.target as HTMLInputElement).value)
      }
    }
    
    <TextField id="id" label="Name" onKeyPress={keyPress} />
    

    Typescript will give you below error ...

    Property 'value' does not exist on type 'EventTarget'.

    Another post on this error: Property 'value' does not exist on type EventTarget in TypeScript

    ... when you access value - e.target.value though the value exists, so you can suppress this error by casting it as HTMLInputElement as shown above.

    In my opinion, you are trying to access e.key, not the e.target.value in onKeyPress handler; as you are most likely to do that in onChange handler.


    Same but, maybe, shorter form:

    type KeyPressType<T = Element> = EventHandler<KeyboardEvent<T>>
    
    const keyPress: KeyPressType<HTMLInputElement> = (e) => {
      if (e.key === 'Enter') {
        console.log('Do login', (e.target as HTMLInputElement).value)
      }
    }
    

    Question: What's the type of e?

    Answer: It is KeyboardEvent<HTMLInputElement>