自定义Form Hook的TypeScript类型标注问题
自定义Form Hook的TypeScript类型标注问题(useReducer相关)
问题背景
我已掌握TypeScript基础,但在给useReducer这类高级概念加类型标注时卡壳了。下面是我写的自定义Form Hook代码,应该存在类型标注错误:
import { useCallback, useReducer } from 'react'; interface Inputs { id: string; value: string; inputIsValid: boolean; } interface FormState { inputs: Inputs[]; isValid: boolean; } interface FormAction { inputs: Inputs; type: string; value: string; inputId: string; isValid: boolean; formIsValid: boolean; } const formReducer = (state: FormState, action: FormAction): FormState => { switch (action.type) { case 'INPUT_CHANGE': let formIsValid = true; for (const inputId in state.inputs) { if (!state.inputs[inputId]) continue; if (inputId === action.inputId) formIsValid = formIsValid && action.isValid; else formIsValid = formIsValid && state.inputs[inputId].inputIsValid; } return { ...state, inputs: { ...state.inputs, [action.inputId]: { value: action.value, isValid: action.isValid }, }, isValid: formIsValid, }; case 'SET_DATA': return { inputs: action.inputs, isValid: action.formIsValid, }; default: return state; } }; export const useForm = ( initialInputs: Inputs, initialFormValidity: boolean ) => { const [formState, dispatch] = useReducer(formReducer, { inputs: initialInputs, isValid: initialFormValidity, }); const inputHandler = useCallback( (id: string, value: string, isValid: boolean) => { dispatch({ type: 'INPUT_CHANGE', value: value, isValid: isValid, inputId: id, }); }, [] ); const setFormData = useCallback( (inputData, formValidity: boolean) => { dispatch({ type: 'SET_DATA', inputs: inputData, formIsValid: formValidity, }); }, [] ); return [formState, inputHandler, setFormData]; };
我还有一个用这个Hook的自定义Input组件,代码来自Max Schwarzmueller的MERN栈课程(课程没给类型标注)。我学过他的TypeScript课但还没看完,核心问题出在useReducer上,报错信息如下:
报错信息
No overload matches this call. Overload 1 of 5, '(reducer: ReducerWithoutAction<any>, initializerArg: any, initializer?: undefined): [any, DispatchWithoutAction]', gave the following error. Argument of type '(state: FormState, action: FormAction) => FormState' is not assignable to parameter of type 'ReducerWithoutAction<any>'. Overload 2 of 5, '(reducer: (state: FormState, action: FormAction) => FormState, initialState: FormState, initializer?: undefined): [FormState, Dispatch<...>]', gave the following error. Type 'Inputs' is not assignable to type 'Inputs[]'.ts(2769) form-hook.tsx(10, 3): The expected type comes from property 'inputs' which is declared here on type 'FormState'
解决方法
我调整了两处关键类型定义,解决了问题:
- 把
useForm函数的initialInputs参数类型从Inputs改成Inputs[],和FormState里inputs的数组类型匹配 - 将
FormAction从单一接口改成联合类型,明确每个action的专属结构,去掉冗余属性:
type FormAction = | { type: 'INPUT_CHANGE'; value: string; inputId: string; isValid: boolean } | { type: 'SET_DATA'; formIsValid: boolean; inputs: Inputs[] };
这个方案能很好地解决useReducer的类型不匹配问题,推荐给所有想搞懂TypeScript中useReducer用法的开发者。
内容的提问来源于stack exchange,提问作者HarrySIV
相关产品推荐
相关产品推荐

