我试图创建一个反应钩使用TS。作为参数,我给出了键和将被分配给这个键的值。我希望通过读取给定的键来限制值的类型。
export function useFormFields<T, K extends keyof T>(initialValues: T) {
const [formFields, setFormFields] = useState<T>(initialValues)
const createChangeHandler = (key: K, value: T[K]) => {
setFormFields((prev: T) => ({ ...prev, [key]: value }))
}
return { formFields, createChangeHandler }
}当我使用createChangeHandler函数时,关键部分可以工作,但是它结合了值的类型。
假设我有一个对象/接口,如下所示:
interface User {
name: string,
age: number
}我希望crateChangeHandler在下一个示例中抛出一个错误
createChangeHandler('name', 1)
//Works because the combined type are "string" | "number"
//I'd like to have "string" only发布于 2021-03-10 19:50:20
您的问题是,您为K泛型类型参数获得了错误的范围。当一个泛型函数被调用时,它的所有类型参数都会立即被指定;不能将指定类型参数推迟到稍后的时间。当您调用useFormFields时,您知道T是什么,但不知道K是什么。但是,对于函数的版本,无论如何都会推断出K。由于没有什么可以帮助编译器推断,所以它将被扩展到它的约束,即keyof T。
相反,您希望createChangeHandler()本身在K中是通用的,因此K的类型参数应该移到它的作用域:
function useFormFields<T>(initialValues: T) {
const [formFields, setFormFields] = useState<T>(initialValues)
const createChangeHandler = <K extends keyof T>(key: K, value: T[K]) => {
setFormFields((prev: T) => ({ ...prev, [key]: value }))
}
return { formFields, createChangeHandler }
}这给出了您想要的行为:
createChangeHandler("age", 10); // okay
createChangeHandler('name', 1); // error!
// Argument of type 'number' is not assignable to parameter of type 'string'发布于 2021-03-10 19:47:12
您的函数useFormFields是泛型的,但是从它返回的createChangeHandler函数不是。当您调用useFormFields时,从编译器的角度来看,您已经将这些类型固定为一个联合。这就是编译器所看到的:
const handler: (key: keyof User, value: User[keyof User]) => void =
useFormFields(someUser).createChangeHandler您需要将泛型移到返回的函数上,以便在处理程序的调用站点缩小类型:
export function useFormFields<T>(initialValues: T) {
const [formFields, setFormFields] = useState<T>(initialValues)
const createChangeHandler = <K extends keyof T>(key: K, value: T[K]) => {
setFormFields((prev: T) => ({ ...prev, [key]: value }))
}
return { formFields, createChangeHandler }
}现在编译器看到:
const handler: <K extends keyof User>(key: K, value: User[K]) => void =
useFormFields(someUser).createChangeHandler;当您更改键输入时,它将能够缩小值类型。
https://stackoverflow.com/questions/66571059
复制相似问题