我想获取一些对象并通过键将其修改为字符串并返回对象。
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
上出错
“类型'string'不能用于索引类型'T'.ts(2536)”
我该如何解决? 谢谢
答案 0 :(得分:2)
由于通用类型T
可以用扩展了Record<string, string>
的任何类型实例化而发生错误。
考虑类型
interface Inputs {x: string; y: string}
Inputs
扩展Record<string, string>
时,允许使用任意字符串对其进行索引将是完全不安全的。
换句话说,我们不想要以下内容
const i: Inputs = {x: "A", y: "B"};
const [inputs, setInputs] = useInputs(i);
setInputs("name")(event);
因为Inputs
没有name
属性。
因此,您的内部类型UpdateFunction
必须采用一个参数,该参数是任何实例化实例化的T
类型的有效键。像keyof T
中这样写成(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
的类型,该参数提供了从React.FocusEvent<HTMLInputElement>
开始更新属性的值。到{target: {value: T[keyof T]}}
出于相同的原因,通用的T
可以用其 values 是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
的{{1}}始终是value
。