React Typescript: получение ошибки типа при динамической установке значений в обработчике изменений

#reactjs #typescript #react-component

#reactjs #typescript #реагирующий компонент

Вопрос:

Я пытаюсь создать форму динамически на основе массива объектов.

Цель здесь — динамически создавать учетные записи пользователей по нажатию кнопки «Добавить пользователя» и отправлять весь объект состояния пользователей в серверную часть.

Получение этой ошибки ‘Элемент неявно имеет тип ‘any’, потому что тип ‘{ name: string; age: string; }’ не имеет индексной подписи‘.

Я новичок в react! Помощь была бы оценена.

Что я делаю не так?

 import * as React from "react";

interface State{
  users:User[]
}
interface Props{

}
interface User{
  name:string,
  age:number;
}

class App extends React.Component<Props,State> {

   state = {
      users: [{name:"", age:""}],
   }

   handleChange = (value:number,event  : React.ChangeEvent<HTMLInputElement>) => {
    let users = [...this.state.users];
    console.log(event.target.value);
    users[value][event.target.name] = event.target.value;
    this.setState({ users }, () => console.log(this.state.users))
   }

   addUser = () => {    
    this.setState((prevState) => ({
      users: [...prevState.users, {name:"", age:""}],
    }));
   }

   handleSubmit = (e:any) => { 
       e.preventDefault();
       console.log(this.state.users) 
   }

   render() {
     let { users} = this.state
     return (
      <form onSubmit={this.handleSubmit} >
        <button onClick={this.addUser}>Add new cat</button>
        {
          users.map((val, id)=> {
            return (
              <div key={id}>
                <input
                  type="text"
                  name="name"                 
                  value={users[id].name}                   
                  onChange = {(e) =>this.handleChange(id,e)}
                />

                <input
                  type="text"
                  name="age"
                  value={users[id].age}                  
                  onChange = {(e) => this.handleChange(id,e)}
                />
              </div>
            )
          })
        }
        <input type="submit" value="Submit" /> 
      </form>
    )
  }
}
export default App;
  

Ответ №1:

Тип event.target.value является строковым и не обязательно 'name' | 'age' таким при вызове:

users[value][event.target.name] = event.target.value;

Typescript не может быть уверен, что users[value] будет иметь этот индекс. Вот почему вы можете либо изменить пользовательский интерфейс:

 interface User {
    name:string,
    age:number;
    [key: string]: string | number
}
  

или вы можете проверить, соответствует ли ключ ожидаемому значению:

 const keyName = event.target.name
if (keyName === 'name' || keyName === 'age') {
    users[value][keyName] = event.target.value;
}
  

Комментарии:

1. Идеально! Большое спасибо

Ответ №2:

Во-первых, интерфейс для пользователя неправильный. возраст преобразуется в число, и вы устанавливаете возраст в пустую строку «».

Во-вторых, когда вы используете Array.prototype.map, вы не используете индекс [id]. Реализация вашей функции map () выглядит немного странно. Из MDN

Метод map() создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.

Вы можете прочитать больше о map здесь

 import * as React from "react";

interface Props{

}

interface User {
  name: string;
  age: number | string;
}

interface State {
  users: User[];
}

class App extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      users: [{ name: "", age: "" }]
    };
  }

  handleChange = (value: number, event: React.ChangeEvent<HTMLInputElement>) => {
    let users = [...this.state.users];
    users[value][event.target.name] = event.target.value;
    this.setState({ users }, () => console.log(this.state.users));
  };

  addUser = () => {
    this.setState(prevState => ({
      users: [...prevState.users, { name: "", age: "" }]
    }));
  };

  handleSubmit = (e: any) => {
    e.preventDefault();
    console.log(this.state.users);
  };

  render() {
    const { users } = this.state;
    return (
      <form onSubmit={this.handleSubmit}>
        <button onClick={this.addUser}>Add new cat</button>
        {users.map((user, id) => {
          return (
            <div key={id}>
              <input
                type="text"
                name="name"
                value={user.name}
                onChange={e => this.handleChange(id, e)}
              />

              <input
                type="text"
                name="age"
                value={user.age}
                onChange={e => this.handleChange(id, e)}
              />
            </div>
          );
        })}
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
export default App;