通用onChange事件在Select控件中失效的问题求助
Select控件使用通用useForm的onChange事件类型不兼容问题
错误信息
Type '(e: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => void' is not assignable to type '(event: SelectChangeEvent<string>, child: ReactNode) => void'. Types of parameters 'e' and 'event' are incompatible. Type 'SelectChangeEvent<string>' is not assignable to type 'ChangeEvent<HTMLInputElement | HTMLSelectElement>'. Type 'Event & { target: { value: string; name: string; }; }' is missing the following properties from type 'ChangeEvent<HTMLInputElement | HTMLSelectElement>': nativeEvent, isDefaultPrevented, isPropagationStopped, persistts(2322) Select.tsx(19, 3): The expected type comes from property 'onChange' which is declared here on type 'IntrinsicAttributes & Props'
相关代码
useForm.tsx
import { ChangeEvent, useState } from 'react'; interface FormFieldInitialValues { [key: string]: string; } const useForm = (formFieldInitialValues: FormFieldInitialValues) => { const [values, setValues] = useState<FormFieldInitialValues>( formFieldInitialValues ); const handleInputChange = ( e: ChangeEvent<HTMLInputElement | HTMLSelectElement> ) => { const { name, value } = e.target; setValues({ ...values, [name]: value, }); }; return { values, setValues, handleInputChange, }; }; export default useForm;
报错的Select控件代码
<Controls.Select name="classSelect" label="Class" value={values.classSelect} onChange={handleInputChange} // 此处报错 options={GetClassesService()} ></Controls.Select>
可正常工作的Input控件代码
<Controls.Input name="lastName" label="Last Name" value={values.lastName} onChange={handleInputChange} />
解决方案
问题根源在于:自定义Controls.Select的onChange事件使用的是UI库(如Ant Design)的SelectChangeEvent类型,而非标准HTML元素的ChangeEvent,两者类型结构不匹配导致报错。
推荐方案:兼容两种事件类型
修改useForm.tsx中的handleInputChange函数,使其同时支持标准ChangeEvent和UI库的SelectChangeEvent:
import { ChangeEvent, useState, ReactNode } from 'react'; // 若使用Ant Design,需导入SelectChangeEvent类型 import type { SelectChangeEvent } from 'antd/es/select'; interface FormFieldInitialValues { [key: string]: string; } // 定义兼容两种事件的联合类型 type FormChangeEvent = | ChangeEvent<HTMLInputElement | HTMLSelectElement> | (SelectChangeEvent<string> & { target: { name: string } }); const useForm = (formFieldInitialValues: FormFieldInitialValues) => { const [values, setValues] = useState<FormFieldInitialValues>( formFieldInitialValues ); const handleInputChange = ( e: FormChangeEvent, child?: ReactNode // 匹配Select控件onChange的第二个参数 ) => { let name: string; let value: string; // 区分事件类型并提取name和value if ('nativeEvent' in e) { // 标准Input/原生Select的ChangeEvent name = e.target.name; value = e.target.value; } else { // UI库的SelectChangeEvent name = e.target.name; value = e.value; } setValues({ ...values, [name]: value, }); }; return { values, setValues, handleInputChange, }; }; export default useForm;
简化方案:类型断言(不推荐)
若无需严格类型检查,可在使用时直接断言类型(存在类型安全风险):
<Controls.Select name="classSelect" label="Class" value={values.classSelect} onChange={handleInputChange as (event: SelectChangeEvent<string>, child: ReactNode) => void} options={GetClassesService()} ></Controls.Select>
内容的提问来源于stack exchange,提问作者Suraj Rai
相关产品推荐
相关产品推荐

