Home > Software engineering >  TS7053: Element implicitly has an 'any' type because expression of type 'string'
TS7053: Element implicitly has an 'any' type because expression of type 'string'

Time:09-14

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

CodePudding user response:

Your variable values is of the type { username: string; email: string; password: string; confirmPassword: string; }. Accessing its contents can be done by calling values.username or values['username'].

Typescript can even infer something like this:

let key = 'username'
let username = values[key]

This is because key does not have the general type string in this instance, but is known to be of the type 'username', which is known to be able to index values.

Your code contains the line value={values[input.name]}. The variable input.name is of the type string. However, values cannot be indexed by any string, only specific ones. Typescript only knowns that input.name is a string. If you are certain, that your string can index the type, you can typecast the string with index.name as keyof typeof values and typescript should stop complaining.

Notice, however, that you are trying to use input.name as the key for values, but the names are "UserName" and "Email". You should use input.id instead as the ids match the actual keys. Capitalisation is important.

Now the result of values[index.name as keyof typeof values] may still be of any type, because typescript does not know which value is actually returned. Because everything in values is a string you can just typecast is to string. In total you get values[index.name as keyof typeof values] as string.

CodePudding user response:

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.

  • Related