76

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'.
Kokodoko
  • 26,167
  • 33
  • 120
  • 197
  • 1
    Possible duplicate of [Typescript: React event types](https://stackoverflow.com/questions/42081549/typescript-react-event-types) – jonrsharpe Aug 13 '17 at 21:49
  • Thanks... that shows the type of the event `onChange(e: React.FormEvent)`. But I still can't find the type of the change handler in props... – Kokodoko Aug 13 '17 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'`. – Nitzan Tomer Aug 13 '17 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` – Kokodoko Aug 13 '17 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 – Nitzan Tomer Aug 13 '17 at 22:52
  • Sorry but if I update using `npm install react react-dom` it remains at 15.6.1 even if for a completely new project. Also, the question is not entirely answered, but I can make a new question asking only for the type of the callback function? – Kokodoko Aug 13 '17 at 23:34
  • That's basically the same exact question. Have you tried the solution presented in the 2nd answer in referenced question? – Nitzan Tomer Aug 13 '17 at 23:53

5 Answers5

184

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>.

basarat
  • 261,912
  • 58
  • 460
  • 511
  • 20
    This is the part where I cry in gratitude. No more dredging through opaque documentation. – Jason Dec 14 '17 at 04:44
  • 4
    Oh thanks so much for this. such a simple trick and so many hours of pain gone :) – Isen Sep 16 '20 at 10:06
  • 1
    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! – counterbeing Jul 06 '21 at 20:16
  • Where are you seeing this secret tip? PHPStorm doesn't have an option like this as far as I can see. – Jamie Hutber Jul 28 '21 at 13:34
  • How you can infer it like that? – Jorge Monroy Apr 06 '22 at 16:39
  • For those missing what the poster is saying: they've coded a very simple test case, and found out the type of the event argument through their IDE's Typescript Intellisense. PHPStorm supports this, as does any major IDE on the planet. – Leland Feb 27 '23 at 13:32
18

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"
}
t3__rry
  • 2,817
  • 2
  • 23
  • 38
Thulasiram
  • 8,432
  • 8
  • 46
  • 54
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){
 }
Rishabh Gusain
  • 683
  • 1
  • 6
  • 23
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.

Amin NAIRI
  • 2,292
  • 21
  • 20
-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.

LEMUEL ADANE
  • 8,336
  • 16
  • 58
  • 72