Reputation: 43
Trying out TypeScript for a React project and I'm stuck on this error.
TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ paymentMethod: string; amount: string; receiptCode: string; paymentDate: string; paymentSourceID: string; }'. No index signature with a parameter of type 'string' was found on type '{ paymentMethod: string; amount: string; receiptCode: string; paymentDate: string; paymentSourceID: string; }'
when i try setInputs()
setInputs(inputs => ({...inputs, [inputs.field[eventName]]: eventValue}));
and this is my component.
import React, {useState} from 'react';
import {DatePicker} from "jalali-react-datepicker";
import axios from "axios";
import PaymentFormClasses from './PaymentForm.module.css';
import PaymentCard from "../../Cards/PaymentCard/PaymentCard";
import Card from "../../Cards/Card";
interface PaymentForm {
field: {
paymentMethod: string,
amount: string,
receiptCode: string,
paymentDate: string,
paymentSourceID: string
}
}
const PaymentForm = () => {
const [inputs, setInputs] = useState<PaymentForm>({
field: {
paymentMethod: '',
amount: '',
receiptCode: '',
paymentDate: '',
paymentSourceID: 'paymentSourceID'
}
});
const changedHandler = (e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLSelectElement>) => {
console.log(typeof e.target.name);
const eventName = e.target.name;
const eventValue = e.target.value;
setInputs(inputs => ({...inputs, [inputs.field[eventName]]: eventValue}));
console.log(e.target.value);
}
return (
<>
</>
);
};
export default PaymentForm;
Upvotes: 0
Views: 1615
Reputation: 42228
You need to assert that e.target.name
, which is always just string
, is in fact a valid key of inputs.field
.
const eventName = e.target.name as keyof PaymentForm['field'];
However your update syntax is not right. You are setting top-level properties of inputs and you are using the value of inputs.field[eventName]
as the property name.
You could do a nested update:
setInputs(inputs => ({
...inputs,
field: {
...inputs.field,
[eventName]: eventValue
}
}));
But why do we need to have this field
property at all? It's the only property in inputs
so why don't we just make it be the entire state.
interface Fields {
paymentMethod: string;
amount: string;
receiptCode: string;
paymentDate: string;
paymentSourceID: string;
}
const PaymentForm = () => {
const [fields, setFields] = useState<Fields>({
paymentMethod: "",
amount: "",
receiptCode: "",
paymentDate: "",
paymentSourceID: "paymentSourceID"
});
const changedHandler = (
e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
) => {
setFields((fields) => ({
...fields,
[e.target.name as keyof Fields]: e.target.value
}));
};
return <></>;
};
Upvotes: 2
Reputation: 841
Your eventName can be a union of the field keys. Try this.
type EventName = 'paymentMethod' | 'amount' | 'recieptCode' ...etc;
const eventName = e.target.name as EventName; // OR
const eventName = e.target.name as keyof PaymentForm['field'];
Upvotes: 1