Joff
Joff

Reputation: 12197

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

Upvotes: 8

Views: 13564

Answers (4)

Jitendra Kumar
Jitendra Kumar

Reputation: 2221

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

Upvotes: 1

SupergroverNN
SupergroverNN

Reputation: 31

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

Upvotes: 3

Oblosys
Oblosys

Reputation: 15136

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

Upvotes: 15

Tomas Kirda
Tomas Kirda

Reputation: 8413

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

Upvotes: 2

Related Questions