14

The following code in TypeScript with React is outputting the following error.

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

import React, { Component } from 'react';

class InputForm extends React.Component<any ,any> {
  state = {
    userInput: ''
  };

  handleUserInput = (e: React.FormEvent<HTMLInputElement>): void => {
    this.setState({
      userInput: e.target.value
    });
  }

  // Working code from 42081549
  // Not relevant to this project
  update = (e: React.FormEvent<HTMLInputElement>): void => {
    this.props.login[e.currentTarget.name] = e.currentTarget.value
  }

  submitMessage = (e: React.FormEvent<HTMLFormElement>): void => {
    e.preventDefault();
    this.props.sendUserMessage(this.state.userInput)
  }

  render() {
    return (
      <form className="chat-input-form" onSubmit={this.submitMessage}>
        <input value={this.state.userInput} onChange={this.handleUserInput}/>
        <button type="submit" />
      </form>
    );
  }

}

export default InputForm;

I am currently using:

  • "@types/react": "^16.0.40",

  • "react": "^16.2.0",

  • "typescript": "^2.7.2",

This could be considered a follow-up to Typescript: React event types however it is not a duplicate as working code provided in by Nitzan Tomer in this answer is currently not working in my specific use case.

EDIT As mentioned above, NOT a duplicate of Typescript: React event types, the solution provided in that question is not working in this case, and therefore could be a different cause.

My tsconfig.json file is as follows:

{
  "compilerOptions": {
    "target": "es5",                          
    "module": "commonjs", 
    "lib": ["esnext", "dom"],
    "jsx": "react",                           
    "sourceMap": true,                        
    "outDir": "./dist/",                      
    "strict": true,                        
    "noImplicitAny": true,                   
    "esModuleInterop": true                 
  }
}
tomhughes
  • 4,597
  • 2
  • 24
  • 33

2 Answers2

17

The problem is that you're using e.target.value instead of e.currentTarget.value.

As you can see in the definition file:

interface SyntheticEvent<T> {
    ...
    currentTarget: EventTarget & T;
    ...
    target: EventTarget;
    ...
}
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • The update() method is giving the same error despite using e.currentTarget. – tomhughes Mar 07 '18 at 12:52
  • I'm compiling it with `typescript@2.7.2` and `@types/react@16.0.40` and it compiles just fine when I make the fix in my answer. Maybe you have something weird in your environment. Create a new directory, and install things there from fresh, then make sure you compile it from there: `./node_modules/.bin/tsc ...` and see if there's a change. – Nitzan Tomer Mar 07 '18 at 12:56
  • Same issue in a fresh directory with InputForm.tsx as the only file, running the command `/node_modules/.bin/tsc InputForm.tsx --jsx react` with the same version numbers as above. – tomhughes Mar 07 '18 at 13:03
  • I don't know what to tell you. Your code compiles just fine for me, with the same versions for ts and the react types. It must be something in your environment that is messed up, but I don't know what. – Nitzan Tomer Mar 07 '18 at 13:09
  • Not sure if I'm misunderstanding but when I open up the type definitions (@Types/react/global.d.ts) the interface for EventTarget is an empty object. If I was amend this to an interface where value is expected as string the error goes away. Am I importing the type definitions incorrectly? – tomhughes Mar 07 '18 at 13:25
  • `EventTarget` isn't what you need, notice that the `currentTarget` property is of type `EventTarget & T`. In your case, `T` is `HTMLFormElement` which has the property `value`. – Nitzan Tomer Mar 07 '18 at 13:51
7

To elaborate a bit on Nitzan Tomer's answer...

You used to be able to use e.target.value in this way where target would be generic, in this case: HTMLInputElement. The code was reverted to make e.currentTarget generic and make e.target not generic (hard-coded to EventTarget). EventTarget doesn't have a value attribute.

The reason lies in the difference between currentTarget and target. When you refer to target, you refer to the element which triggered the event. If you have a button, with some icon in it. If the icon is directly clicked, then it would be the target. At compile time, you cannot know what element type will trigger the click, but you can know which element the eventListener is registered on. Thus currentTarget is generic.

Further, target is rarely what you want. You typically want the element, where you attached the eventListener.

The Github comment providing the above rationale.
The Github PR where target was made /not/ generic.

cdosborn
  • 3,111
  • 29
  • 30