Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React + Typescript: How to type event.target.name to state?

I have som react state that was defined as an interface and has specificall named keys...

I tried a solution below that should technically work based on the state keys, but it still gives me the error

{ [x: string]: string; }' provides no match for the signature  ...

What is the best way to do this...

interface State {
    responses: string,
    comments: string,
}


  state = {
    responses: '',
    comments: '',
  };

  handleChange = (e: React.ChangeEvent<HTMLInputElement>, value: string): void => {
    const key = e.currentTarget.name;
    Object.keys(this.state).forEach(k => {
      if (k === key) this.setState({ [e.currentTarget.name]: value });
    })
  }
like image 350
Joff Avatar asked Jul 13 '18 13:07

Joff


4 Answers

public onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  this.setState({
    [e.currentTarget.name]: e.currentTarget.value
  } as { [K in keyof IState]: IState[K] });
};

IState - interface of this.state

like image 42
SupergroverNN Avatar answered Nov 09 '22 03:11

SupergroverNN


The return type of Object.keys() is the generic string[] rather than an array of the union of the keys of the object, so it's probably tricky to infer the correct types here. Moreover, in my experience, smart solutions have a tendency to break when newer versions of TypeScript or package type definitions are released, so in this case I would just help TypeScript with a signature on to the argument of setState:

handleChange = (e: React.ChangeEvent<HTMLInputElement>, value: string): void => {
  const key = e.currentTarget.name;

  if (Object.keys(this.state).includes(key)) {
    this.setState({[key]: value } as Pick<State, keyof State>);
  }
}
like image 62
Oblosys Avatar answered Nov 09 '22 03:11

Oblosys


One option would be instead of iterating through keys, to use switch statement. Although it will produce more code:

switch (key) {
  case 'responses':
    this.setState({ responses: value });
    break;
  case 'comments':
    this.setState({ comments: value });
    break;
}
like image 43
Tomas Kirda Avatar answered Nov 09 '22 03:11

Tomas Kirda


If you declare state with type number then use this code for update state:

 this.setState({ ...this.state, [event.currentTarget.name]: Number(event.target.value) });

If you declare state with type string then use this code for update state:

this.setState({ ...this.state, [event.currentTarget.name]: event.target.value });

Full code:

onChange =(event: React.ChangeEvent<HTMLInputElement>) => {
            this.setState({ ...this.state, [event.currentTarget.name]: Number(event.target.value) });
        }
like image 30
Jitendra Suthar Avatar answered Nov 09 '22 03:11

Jitendra Suthar