Reputation: 7537
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'.
Upvotes: 531
Views: 1027101
Reputation: 12765
Generally event handlers should use e.currentTarget.value
:
You can read why it so here (Revert "Make SyntheticEvent.target generic, not SyntheticEvent.currentTarget.").
const onChange = (e: React.ChangeEvent<HTMLInputElement >) => {
const newValue = e. currentTarget.value;
}
Upvotes: 990
Reputation: 61
onChange=event: (React.ChangeEvent<HTMLInputElement>)=>{
const newValue = e.target.value;
}
Upvotes: 6
Reputation: 111
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);
};
Upvotes: 1
Reputation: 860
const onChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const newValue = (event.target || event.currentTarget) as HTMLInputElement;
return newValue.value;
}
Upvotes: 10
Reputation: 21
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>
Upvotes: 2
Reputation: 49759
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
Upvotes: 10
Reputation: 67
Convert string to number simple answer
<input
type="text"
value={incrementAmount}
onChange={(e) => {
setIncrementAmmount(+e.target.value);
}}
/>
Upvotes: 2
Reputation: 1603
const event = { target: { value: 'testing' } as HTMLInputElement };
handleChangeFunc(event as ChangeEvent<HTMLInputElement>);
this work for me.
Upvotes: 0
Reputation: 1408
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);
};
Upvotes: 29
Reputation: 3267
This works for me also it is framework agnostic.
const handler = (evt: Event) => {
console.log((evt.target as HTMLInputElement).value))
}
Upvotes: 7
Reputation: 491
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;
};
Upvotes: 26
Reputation: 11264
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}
/>
Upvotes: 0
Reputation: 47
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.
Upvotes: 5
Reputation: 921
You can do the following:
import { ChangeEvent } from 'react';
const onChange = (e: ChangeEvent<HTMLInputElement>)=> {
const newValue = e.target.value;
}
Upvotes: 92
Reputation: 1617
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>
);
}
Upvotes: 15
Reputation: 1569
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.
For more reference you can check other available interface here
Upvotes: 4
Reputation: 1950
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);
};
Upvotes: 11
Reputation: 7103
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} />
)
Upvotes: 12
Reputation: 3592
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
.
Upvotes: 2
Reputation: 1315
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;
}}
Upvotes: 6
Reputation: 1463
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;
}
Upvotes: 7
Reputation: 4136
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;
Upvotes: 259
Reputation: 3423
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.
Upvotes: 13