typescript - 打字稿。定义泛型键作为字符串
问题描述
我想获取一些对象并通过键将其修改为字符串并返回对象。
const useInputs = <T extends Record<string, string>>(defaultValue: T) => {
const [inputsData, setInputsData] = useState<T>(defaultValue)
type UpdateFunction = (key: string) => (el: React.FocusEvent<HTMLInputElement>) => void
const updateData: UpdateFunction = key => el => {
const newInputsData = {...inputsData}
newInputsData[key] = el.target.value
setInputsData(newInputsData)
}
return { inputsData, updateData }
}
但我对newInputsData[key] = el.target.value
“类型'字符串'不能用于索引类型'T'.ts(2536)”有错误
我该如何解决这个问题?谢谢
解决方案
出现该错误是因为泛型类型T
可以使用扩展的任何类型实例化Record<string, string>
。
考虑类型
interface Inputs {x: string; y: string}
虽然Inputs
extends Record<string, string>
,允许使用任意字符串对其进行索引是完全不安全的。
换句话说,我们不想要以下
const i: Inputs = {x: "A", y: "B"};
const [inputs, setInputs] = useInputs(i);
setInputs("name")(event);
因为Inputs
没有name
财产。
因此,您的内部类型 ,UpdateFunction
必须采用一个参数,该参数是T
任何实例化类型的有效键。这样的类型写成keyof T
in (key: keyof T) => (el: React.FocusEvent<HTMLInputElement>) => void
。
放在一起应该是这样的
const useInputs = <T extends Record<string, string>>(defaultValue: T) => {
const [inputsData, setInputsData] = useState<T>(defaultValue);
type UpdateFunction = (key: keyof T) => (el: {target: {value: T[keyof T]}}) => void;
const updateData: UpdateFunction = key => el => {
const newInputsData = {...inputsData};
newInputsData[key] = el.target.value;
setInputsData(newInputsData)
};
return [inputsData, updateData] as const;
};
注意外部函数的返回值的调整,它允许常规使用你的钩子。
const [inputs, setInputs] = useInputs(...);
与非正统相反
const {inputsData, updateData} = useInputs(...);
此外,请注意,为了进行上述类型检查,我们还必须调整第二个参数的类型el
,它提供了使用 from React.FocusEvent<HTMLInputElement>
to更新属性的值,{target: {value: T[keyof T]}}
原因与上面讨论的相同,泛型T
可以被实例化具有其值是string
诸如"despair"
和的子类型的属性"elation"
。
替代方法包括使用更精确的类型,el
例如
Omit<React.FocusEvent<HTMLInputElement>, "target"> & {
target: { value: T[keyof T] };
}
移动更改方式 useInput
是通用的,从整个输入对象的类型到该对象的属性键。
const useInputs = <K extends string>(defaultValue: Record<K, string>) => {
const [inputsData, setInputsData] = useState(defaultValue);
type UpdateFunction = (
key: K
) => (el: React.FocusEvent<HTMLInputElement>) => void;
const updateData: UpdateFunction = key => el => {
const newInputsData = { ...inputsData };
newInputsData[key] = el.target.value;
setInputsData(newInputsData);
};
return [inputsData, updateData] as const;
};
我更喜欢最后一个,因为HTMLInputElement
'svalue
总是一个string
.
推荐阅读
- java - H2 问题:请求在 H2 控制台中工作,而不是在 jUnit 测试中
- sql - 拆分日期列,然后按日期分组并在 SQL 中获取最大值
- linux - 在 shell 脚本中将交互式命令作为后台进程运行
- react-native - React-navigation 5x 使用 Stack.Screen screenProps
- c# - 如何在套接字编程C#中处理接收到的TCP数据包
- sql-server - SQL Server 2019 UDF 中的 @@ROWCOUNT 错误
- kubectl - 如何在不同 kubeconfig yaml 文件中描述的不同 Kubernetes 上下文之间快速切换?
- c# - 错误 [No related source lines] 仅在 1 个数据集上,仅在本地机器上
- amazon - 如何使用亚马逊 MWS api 创建产品
- javascript - 如何在不出现 429 错误的情况下进行多次 fetch 调用?