Typescript input onchange event.target.value
Asked Answered
G

23

502

In my react and typescript app, I use:

onChange={(e) => data.motto = (e.target as any).value}

How do I correctly define the typings for the class, so I wouldn't have to hack my way around the type system with any?

export interface InputProps extends React.HTMLProps<Input> {
...

}

export class Input extends React.Component<InputProps, {}> {
}

If I put target: { value: string }; I get :

ERROR in [default] /react-onsenui.d.ts:87:18
Interface 'InputProps' incorrectly extends interface 'HTMLProps<Input>'.
  Types of property 'target' are incompatible.
    Type '{ value: string; }' is not assignable to type 'string'.
Gettings answered 18/11, 2016 at 11:46 Comment(0)
D
940

Generally event handlers should use e.currentTarget.value, e.g.:

const onChange = (e: React.FormEvent<HTMLInputElement>) => {
  const newValue = e.currentTarget.value;
}

You can read why it so here (Revert "Make SyntheticEvent.target generic, not SyntheticEvent.currentTarget.").

UPD: As mentioned by @roger-gusmao ChangeEvent more suitable for typing form events.

const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const newValue = e.target.value;
}
Dolan answered 7/3, 2017 at 10:24 Comment(9)
This simply does not work. value is not a property of the interface EventTargetCondemnatory
Of course not EventTarget, but part of HTMLInputElement You can see full definition here github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/…Dolan
Oh sorry, you used currentTarget. In that case yes, it works, but the question was about targetCondemnatory
Yes, you right, but as mentioned in github.com/DefinitelyTyped/DefinitelyTyped/pull/12239 using target incorrect in most cases. Moreover, target does not have T to force us to write correctlyDolan
This didn't work for me, I had to cast the event to React.ChangeEvent<HTMLInputElement> rather than a FormEvent.Chihli
by using e.target.value ,only ChangeEvent worksTricky
React.ChangeEvent<HTMLInputElement> is a very common TypeScript type that is used for this case in React. You can see a list of other common types on this cheat sheet: github.com/typescript-cheatsheets/…Enactment
@AnthonyAvila yeah, right. I do not even remeber why I suggested FormEvent. ChangeEvent is a right versionDolan
FormEvent<HTMLInputElement> and e.currentTarget.value worked for me. Thanks!Redcap
O
250

the correct way to use in TypeScript is

  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
        ...
        <input value={temperature} onChange={this.handleChange} />
        ...
    );
  }

Follow the complete class, it's better to understand:

import * as React from "react";

const scaleNames = {
  c: 'Celsius',
  f: 'Fahrenheit'
};


interface TemperatureState {
   temperature: string;
}

interface TemperatureProps {
   scale: string;

}

class TemperatureInput extends React.Component<TemperatureProps, TemperatureState> {
  constructor(props: TemperatureProps) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {temperature: ''};
  }

  //  handleChange(e: { target: { value: string; }; }) {
  //    this.setState({temperature: e.target.value});  
  //  }


  handleChange(e: React.ChangeEvent<HTMLInputElement>) {
    // No longer need to cast to any - hooray for react!
    this.setState({temperature: e.target.value});
  }

  render() {
    const temperature = this.state.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    );
  }
}

export default TemperatureInput;
Outbreak answered 13/4, 2018 at 15:8 Comment(6)
note: to ensure types are available, add lib: ["dom"] to compilerOptions in tsconfig.jsonLaquitalar
And if you have multiple inputs do you need to make a row for each?Firenew
Another way to make sure 'this' is assigned appropriately in the handleChange function would be to write handleChange as an arrow function i.e. handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.setState(...); }; By doing that, one would no longer have to use the constructor to bind the handleEvent function.Lauder
One more way to handle 'this' instead of using the constructor and bind method would be to use the arrow function in the onChange prop i.e. onChange={e => this.handleChange(e)}Lauder
With these changes I am getting error: No overload matches this call. Overload 1 of 2, '(props: Readonly<Props>): Input', gave the following error. Type '(e: ChangeEvent<HTMLInputElement>) => void' is not assignable to type '(event: CustomEvent<ChangeDetail>) => void'. Can someone please help me?Falco
I found this worked in later versions of react: React.ChangeEventHandler<HTMLInputElement>Columbine
F
90

You can do the following:

import { ChangeEvent } from 'react';

const onChange = (e: ChangeEvent<HTMLInputElement>)=> {
   const newValue = e.target.value;
}
Fortify answered 9/2, 2018 at 6:44 Comment(0)
S
27

ChangeEvent<HTMLInputElement> is the type for change event in typescript. This is how it is done-

import { ChangeEvent } from 'react';

const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value);
};
Seven answered 23/6, 2022 at 5:43 Comment(0)
W
24

we can also use the onChange event fire-up with defined types(in functional component) like as follows:

 const handleChange = (
    e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
  ) => {
        const name = e.target.name;
        const value = e.target.value;
};

Whitecollar answered 24/11, 2021 at 11:23 Comment(0)
C
18

as HTMLInputElement works for me

Continence answered 8/2, 2017 at 4:16 Comment(2)
That doesn't have a .target?Ragout
@Ragout It's the target you're casting as HTMLInputElement. Since the EventTarget is an HTML elementMacilroy
T
14

I use something like this:

import { ChangeEvent, useState } from 'react';


export const InputChange = () => {
  const [state, setState] = useState({ value: '' });

  const handleChange = (event: ChangeEvent<{ value: string }>) => {
    setState({ value: event?.currentTarget?.value });
  }
  return (
    <div>
      <input onChange={handleChange} />
      <p>{state?.value}</p>
    </div>
  );
}
Tickle answered 31/12, 2020 at 16:50 Comment(1)
Finally something worked. I still don't understand how a ChangeEvent<HTMLInputElement> does not have a value on currentTarger or target...Bunko
F
12

The target you tried to add in InputProps is not the same target you wanted which is in React.FormEvent

So, the solution I could come up with was, extending the event related types to add your target type, as:

interface MyEventTarget extends EventTarget {
    value: string
}

interface MyFormEvent<T> extends React.FormEvent<T> {
    target: MyEventTarget
}

interface InputProps extends React.HTMLProps<Input> {
    onChange?: React.EventHandler<MyFormEvent<Input>>;
}

Once you have those classes, you can use your input component as

<Input onChange={e => alert(e.target.value)} />

without compile errors. In fact, you can also use the first two interfaces above for your other components.

Fermentative answered 29/11, 2016 at 14:24 Comment(1)
The value type is not string!Outbreak
E
11

When using Child Component We check type like this.

Parent Component:

export default () => {

  const onChangeHandler = ((e: React.ChangeEvent<HTMLInputElement>): void => {
    console.log(e.currentTarget.value)
  }

  return (
    <div>
      <Input onChange={onChangeHandler} />
    </div>
  );
}

Child Component:

type Props = {
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}

export Input:React.FC<Props> ({onChange}) => (
  <input type="tex" onChange={onChange} />
)
Eyeglass answered 19/7, 2020 at 3:27 Comment(1)
tiny edit remove extraneous parentheses - const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>): void => {Jacquijacquie
A
10

An alternative that has not been mentioned yet is to type the onChange function instead of the props that it receives. Using React.ChangeEventHandler:

const stateChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
    console.log(event.target.value);
};
Abattoir answered 24/7, 2020 at 10:31 Comment(0)
A
8
const handleChange = (
    e: ChangeEvent<HTMLInputElement>
  ) => {
    const { name, value } = e.target;
    this.setState({ ...currentState, [name]: value });
  };

you can apply this on every input element in the form component

Aposiopesis answered 24/11, 2022 at 19:4 Comment(0)
N
6

Here is a way with ES6 object destructuring, tested with TS 3.3.
This example is for a text input.

name: string = '';

private updateName({ target }: { target: HTMLInputElement }) {
    this.name = target.value;
}
Norenenorfleet answered 17/2, 2019 at 15:30 Comment(1)
This is a great answer that works across the board. I was heavy on Angular, was forced onto React for a year, and am now playing with Angular again to stay fresh on it. React provides some really nice event interfaces that Typescript natively lacks. This approach helps get the same desired typing, even in vanilla. Thanks.Cupro
B
5

This is when you're working with a FileList Object:

onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
  const fileListObj: FileList | null = event.target.files;
  if (Object.keys(fileListObj as Object).length > 3) {
    alert('Only three images pleaseeeee :)');
  } else {
    // Do something
  }

  return;
}}
Brooklet answered 27/9, 2019 at 10:17 Comment(0)
T
5

This works for me also it is framework agnostic.

const handler = (evt: Event) => {
  console.log((evt.target as HTMLInputElement).value))
}
Troudeloup answered 26/4, 2022 at 3:32 Comment(0)
S
4

You no need to type if you do this:

<input onChange={(event) => { setValue(e.target.value) }} />

Because if you set a new value with the arrow function directly in the html tag, typescript will understand by default the type of event.

Schatz answered 20/7, 2021 at 14:20 Comment(0)
G
3

Thanks @haind

Yes HTMLInputElement worked for input field

//Example
var elem = e.currentTarget as HTMLInputElement;
elem.setAttribute('my-attribute','my value');
elem.value='5';

This HTMLInputElement is interface is inherit from HTMLElement which is inherited from EventTarget at root level. Therefore we can assert using as operator to use specific interfaces according to the context like in this case we are using HTMLInputElement for input field other interfaces can be HTMLButtonElement, HTMLImageElement etc.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement

For more reference you can check other available interface here

Gobbledygook answered 26/7, 2020 at 16:10 Comment(0)
C
2
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const newValue = (event.target || event.currentTarget) as HTMLInputElement;
    return newValue.value;
}
Chapbook answered 11/12, 2023 at 0:39 Comment(1)
When we can expect not having event.target? I'm interested what case it handles? event.target || event.currentTargetDolan
D
1
  function handle_change(
    evt: React.ChangeEvent<HTMLInputElement>
  ): string {
    evt.persist(); // This is needed so you can actually get the currentTarget
    const inputValue = evt.currentTarget.value;

    return inputValue
  }

And make sure you have "lib": ["dom"] in your tsconfig.

Dustan answered 3/10, 2019 at 12:8 Comment(0)
G
1

Convert string to number simple answer

<input
    type="text"
    value={incrementAmount}
    onChange={(e) => {
      setIncrementAmmount(+e.target.value);
    }}
/>
Gaiter answered 20/9, 2022 at 16:41 Comment(0)
L
1

This worked great for me.

  const [form, setForm] = useState<string>();

  const updateFormState = (event: { target: { value: React.SetStateAction<string | undefined>; }; }) => {
    setForm(event.target.value)
    console.log(form)
  }

And then the form in the return

<form onSubmit={handleClick}>
        <label>Input</label>
        <input value={form} onChange={updateFormState} type='text'></input>
        <button type='submit'>Submit</button>
 </form>
Larrigan answered 3/5, 2023 at 4:1 Comment(0)
T
0
import { NativeSyntheticEvent, TextInputChangeEventData,} from 'react-native';



  // Todo in java script
 const onChangeTextPassword = (text : any) => {
    setPassword(text);
  }
    

// Todo in type script use this

  const onChangeTextEmail = ({ nativeEvent: { text },}: NativeSyntheticEvent<TextInputChangeEventData>) => {
    console.log("________ onChangeTextEmail _________ "+ text);
    setEmailId(text);
  };


 <TextInput
          style={{ width: '100%', borderBottomWidth: 1, borderBottomColor: 'grey', height: 40, }}
          autoCapitalize="none"
          returnKeyType="next"
          maxLength={50}
          secureTextEntry={false}
          onChange={onChangeTextEmail}
          value={emailId}
          defaultValue={emailId}
          
        />

  
Trichiasis answered 20/9, 2021 at 13:33 Comment(0)
A
0
const event = { target: { value: 'testing' } as HTMLInputElement };
handleChangeFunc(event as ChangeEvent<HTMLInputElement>);

this work for me.

Anemology answered 19/9, 2022 at 2:55 Comment(0)
G
0

In case anyone having trouble with event.target.file, you can refer to the following code which solved my problem for my react project.

    const target = event.target as HTMLInputElement;
    const selectedFile: File = (target.files as FileList)[0];
    console.log("Selected File:", selectedFile, event);
  };
Gregg answered 19/2, 2024 at 16:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.