Kokodoko
Kokodoko

Reputation: 28158

Typescript types for React checkbox events and handlers?

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

Upvotes: 82

Views: 136928

Answers (6)

ilovett
ilovett

Reputation: 3388

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

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

Upvotes: 0

Amin NAIRI
Amin NAIRI

Reputation: 2504

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.

Upvotes: 0

Thulasiram
Thulasiram

Reputation: 8552

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"
}

Upvotes: 22

Rishabh Gusain
Rishabh Gusain

Reputation: 687

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){
 }

Upvotes: 0

LEMUEL  ADANE
LEMUEL ADANE

Reputation: 8846

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.

Upvotes: -1

basarat
basarat

Reputation: 276393

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

Upvotes: 209

Related Questions