Search code examples
reactjstypescriptreact-hooksreact-typescript

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ username: string; email: string;


Trying to add typescript to custom React Form Component and can't rid of mistake i don't know how to fix. TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ username: string; email: string; password: string; confirmPassword: string; }'. No index signature with a parameter of type 'string' was found on type '{ username: string; email: string; password: string; confirmPassword: string; }'.

I'm sure there is an answer somewhere, but i can't adjust it to my code as well as can't understand the basic of mistake. Please help me understand

App Component

import React, {useState} from 'react';
import s from './App.module.scss'
import Input from "./components/Input/Input";

function App() {
    const [values, setValues] = useState({
        username: '',
        email: '',
        password: '',
        confirmPassword: '',
    });

    const inputs = [
        {
        id: "username",
        name: "UserName",
        type: "text",
        placeholder: "Username",
        },
        {
            id: "email",
            name: "Email",
            type: "text",
            placeholder: "@gmail.com",
        },
    ]

    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setValues({...values, [e.target.name]: e.target.value});
    }

    return (
        <div className={s.app}>
            <form action="">
                {inputs.map((input) => (
                    <Input
                        key={input.id}
                        id={input.id}
                        name={input.name}
                        placeholder={input.placeholder}
                        type={input.type}
                        value={values[input.name]}
                        onChange={handleChange}
                    />
                ))}
            </form>
        </div>
    );
}

export default App;

Input Component

import React, {FC} from 'react';
import s from './Input.module.scss';

interface InputProps {
    id: string,
    name: string,
    placeholder: string,
    type: string,
    value: string,
    onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
}

const Input: FC<InputProps> = ({id, name, placeholder, type, value, onChange}) => {
    return (
        <div className={s.input}>
            <label htmlFor={id}>
                {name}
            </label>
            <input
                id={id}
                type={type}
                placeholder={placeholder}
                value={value}
                onChange={onChange}
            />
        </div>
    );
};

export default Input;

Source code: https://github.com/Endo-Resu/react-custom-form

Thank you for ur time, advices and help


Solution

  • Solution:

    App component

    import React, { useState } from "react";
    import s from "./App.module.scss";
    import Input from "./components/Input/Input";
    
    function App() {
      const [values, setValues] = useState({
        username: "",
        email: "",
        password: "",
        confirmPassword: ""
      });
    
      const inputs: {
        id: string;
        name: keyof typeof values;
        type: string;
        placeholder: string;
      }[] = [
        {
          id: "username",
          name: "username",
          type: "text",
          placeholder: "Username"
        },
        {
          id: "email",
          name: "email",
          type: "text",
          placeholder: "@gmail.com"
        }
      ];
    
      const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setValues({ ...values, [e.target.name]: e.target.value });
      };
    
      return (
        <div className={s.app}>
          <form action="">
            {inputs.map((input) => (
              <Input
                key={input.id}
                id={input.id}
                name={input.name}
                placeholder={input.placeholder}
                type={input.type}
                value={values[input.name]}
                onChange={handleChange}
              />
            ))}
          </form>
        </div>
      );
    }
    
    export default App;
    

    Explanation:

    As the previous answer explained, the error is in this line value={values[input.name]} and the reason for the error is that the object values cannot be indexed by any random string, the index has to be one of values declared properties (like username).

    The solution is to give inputs.name a type that can be used as index of values:

    const inputs: {
        id: string;
        name: keyof typeof values;
        type: string;
        placeholder: string;
      }[] = ...
    

    Now the property name has a type of whatever keys in values. Now input.name can be used to index values.