83

I'm building something like this React example in Typescript. The goal is to have a parent that has a state, and it creates several stateless child components that pass their clicks back to the parent.

Since the example is in Javascript I have no idea what the types of the input box events and the onChange handlers are...? I've tried several options like React.MouseEvent<HTMLInputElement>, but that's just guesswork...

Parent component create imageRows and pass the handler:

render() {
  <div>
    <ImageRow key={el.url} onChange={this.onChange}/>
  </div>
 }
 // what should the type of e be?
 onChange(e:any){
 }

And the ImageRow component

export interface ImageRowProps { 
  genre: Array<number>
  url: string
  onChange : any // what is the type of the callback function?
}

export class ImageRow extends React.Component<ImageRowProps> {
  render() {
    return <div className="imagerow">
        <input type="checkbox" key={index} onChange={this.props.onChange} defaultChecked={(num == 1)}/>
    </div>
}

EDIT

The similar question only shows the event type, not the handler type. When I change the event type:

onChange(e: React.FormEvent<HTMLInputElement>){
    console.log(e.target.value)
}

I get this error:

Property 'value' does not exist on type 'EventTarget'.
7
  • 1
    Possible duplicate of Typescript: React event types Commented Aug 13, 2017 at 21:49
  • Thanks... that shows the type of the event onChange(e: React.FormEvent<HTMLInputElement>). But I still can't find the type of the change handler in props... Commented Aug 13, 2017 at 21:58
  • Seem like maybe you are using outdated definition files for react? With the newer version it should be something like Property 'value' does not exist on type 'EventTarget & HTMLInputElement'. Commented Aug 13, 2017 at 22:18
  • Hmmm the version seems to be locked? If I update it remains at @types/react": "^15.6.1 but on npm it says the latest version is 16.0.2 Commented Aug 13, 2017 at 22:29
  • Maybe your react is also not updated? In any case, if you have the old version of the definitions then check out the 2nd answer in the question which is marked is duplicated. I'm pretty sure that it will solve your problem, please update if it worked for you so I'll close this one as duplicated Commented Aug 13, 2017 at 22:52

6 Answers 6

210

When in doubt let it infer it for you by using an arrow in position e.g.

enter image description here

Answer

In your case e is React.ChangeEvent<HTMLInputElement>.

Sign up to request clarification or add additional context in comments.

6 Comments

This is the part where I cry in gratitude. No more dredging through opaque documentation.
Oh thanks so much for this. such a simple trick and so many hours of pain gone :)
This should be one of the first things you learn when first starting typescript. This would have saved me so much time over the past years. Thanks!
Where are you seeing this secret tip? PHPStorm doesn't have an option like this as far as I can see.
How you can infer it like that?
|
22

In our application,

console.log(event.target.value); // Not Working (Blank value)

console.log(event.target.checked); // Working Fine ( true / false )

//../src/components/testpage2/index.tsx

import * as React from 'react';
import {  TestInput } from '@c2/component-library';

export default class extends React.Component<{}, {}> {
    state = {
                model: {
                    isUserLoggedIn: true
                }            
            };

    onInputCheckboxChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        console.log(event.target.value); // Not Working
        console.log(event.target.checked); // Working

        const field = event.target.name;
        const model = this.state.model;      
        model[field] = event.target.checked;

        return this.setState({model: model});
    };

    render() {
        return (
            <div>
                <TestInput
                  name="isUserLoggedIn"
                  label="Is User LoggedIn : "
                  type="checkbox"
                  onChange={this.onInputCheckboxChange}
                />
            </div>
        );
    }
}

//=============================================================//

import * as React from 'react';
//import * as cs from 'classnames';

export interface TestInputProps extends React.HTMLAttributes<HTMLInputElement> {
    name: string;
    label: string;
    onChange: React.ChangeEventHandler<HTMLInputElement>;
    placeholder?: string;
    value?: string;
    type?: string;
    error?: string;
    className?: string;
}

export const TestInput : React.SFC<TestInputProps> = ({ name, label, onChange, placeholder, value, type, className, error, ...rest }) => {
    let wrapperClass:string = 'form-group';
    if (error && error.length > 0) {
      wrapperClass += " " + 'has-error';
    }

    return (
        <div className={wrapperClass}>
            <label htmlFor={name}>{label}</label>
            <div className="field">
                <input
                  type={type}
                  name={name}
                  className="form-control"
                  placeholder={placeholder}
                  value={value}
                  onChange={onChange}
                />
                {error && <div className="alert alert-danger">{error}</div>}
            </div>
        </div>
    );
}

TestInput.defaultProps ={
    type: "text"
}

1 Comment

Perfect, thank you: e.target.value == string and e.target.checked == boolean
0

You can use BaseSyntheticEvent as event type as all DOM event in react are not native but Synthetic.

render() {
  <div>
    <ImageRow key={el.url} onChange={this.onChange}/>
  </div>
 }
 // BaseSyntheticEvent is better than 'any'
 onChange(e:BaseSyntheticEvent){
 }

Comments

0

If you hover the type that is available for the property onChange an <input type="checkbox"> you'll see that React gives you a second parameter for getting the checked state of a checkbox.

You can create a handler that will accept the ChangeEvent event that is dispatched by React when the state of this input changes, and a second parameter that is the checked state of that input.

import { ChangeEvent, useCallback } from "react";

const Main = () => {
  const [checked, setChecked] = useState<boolean>(false);

  const handleChecked = useCallback((changeEvent: ChangeEvent, checked: boolean): void => {
    setChecked(checked);
  }, []);

  return (
    <input
      type="checkbox"
      onChange={handleChecked} />
  );
};

Unfortunately, very few documentation is available on the official React documentation for the TypeScript's types but as in every library it is possible to dig into the types using a supported text editor.

Comments

0

You can export interface ImageRowProps extends React.InputHTMLAttributes<HTMLInputElement> {

And then you can extend your spreaded props directly on to the input.

Comments

-1

Just do this:

onChange = (event: Event) => {
      const { value } = event.target as unknown as { value: boolean, };
      setState(value);
};
  
<input type='radio' onChange={this.onChange} />

And the squeegee lines will go away.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.