@kunal panchal 的答案是完全有效的 Javascript,但它确实会导致 Typescript 错误,因为 event.target.id 的类型是 string,所以 Typescript 不确定它是否是 emailNotifications 的有效键。您必须使用as 来断言它是正确的。
!emailNotifications[event.target.id as keyof EmailNotifications]
避免这种情况的一种方法是通过查看input 上的checked 属性而不是切换状态来获取boolean 值。
作为旁注,使用setState 回调获取当前状态是一个很好的最佳实践,这样当多个更新被批处理在一起时,您始终可以获得正确的值。
const _handleEmailNotificationsSettings = (
event: React.ChangeEvent<HTMLInputElement>
) => {
setEmailNotifications(prevState => ({
...prevState,
[event.target.id]: event.target.checked,
}));
};
这可能是复选框的最佳解决方案。
另一种对其他情况更灵活的方法是使用柯里化函数。我们没有从event.target.id 获取属性(它始终是string),而是将property 作为参数传递给每个属性创建单独的处理程序。
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => () => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: !emailNotifications[property]
}));
};
或
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
你可以这样使用:
<input
type="checkbox"
checked={emailNotifications.favourites}
onChange={handleEmailNotificationsSettings("favourites")}
/>
这些解决方案避免了必须在事件处理程序中进行as 断言,但有时它们是不可避免的。我正在使用(Object.keys(emailNotifications) 遍历您的状态,我需要在那里做出断言,因为Object.keys 总是返回string[]。
import React, { useState } from "react";
// I am defining this separately so that I can use typeof to extract the type
// you don't need to do this if you have the type defined elsewhere
const initialNotifications = {
rating: false,
favourites: false,
payments: false,
refunds: false,
sales: false
};
type EmailNotifications = typeof initialNotifications;
const MyComponent = () => {
// you don't really need to declare the type when you have an initial value
const [emailNotifications, setEmailNotifications] = useState(
initialNotifications
);
const handleEmailNotificationsSettings = (
property: keyof EmailNotifications
) => (event: React.ChangeEvent<HTMLInputElement>) => {
setEmailNotifications((prevState) => ({
...prevState,
[property]: event.target.checked
}));
};
return (
<div>
{(Object.keys(emailNotifications) as Array<keyof EmailNotifications>).map(
(property) => (
<div key={property}>
<label>
<input
type="checkbox"
id={property}
checked={emailNotifications[property]}
onChange={handleEmailNotificationsSettings(property)}
/>
{property}
</label>
</div>
)
)}
</div>
);
};
export default MyComponent;