如何为React Hooks的useReducer传递泛型类型
我来帮你搞定这个泛型传递的问题!首先先修正一个语法小错误:你定义的ActionTypes接口写法不对,TypeScript里要定义动作类型枚举,得用enum而不是interface,不然switch case会报错。先把这个改过来:
// 修正ActionTypes定义 enum ActionTypes { FETCH = 'FETCH' } interface TestPayload<T> { list: T[]; } interface State<T> { list: T[]; } interface Action<T> { type: ActionTypes; payload: TestPayload<T>; } export const returnAnyListReducer = <T>( state: State<T>, action: Action<T> ): State<T> => { const { type, payload } = action; switch (type) { case ActionTypes.FETCH: { return ({ ...state, list: payload.list }); } // 别忘了加default case避免TypeScript报错 default: return state; } }
接下来,有两种直观的方式给useReducer传递你的User或AdminUser这类泛型类型:
方式一:显式给useReducer指定泛型参数
React的useReducer支持传入泛型参数,你可以直接指定State<T>和Action<T>的具体类型,同时需要导入React内置的Reducer类型来做约束:
首先定义你的业务类型,比如User:
interface User { id: number; name: string; }
然后在组件里这样用:
import { useReducer, Reducer } from 'react'; // 显式指定initialState的类型,避免空数组被推断成never[] const initialState: State<User> = { list: [] }; // 给useReducer传入Reducer<State<User>, Action<User>>泛型 const [state, dispatch] = useReducer<Reducer<State<User>, Action<User>>>( returnAnyListReducer, initialState );
这样之后,dispatch的时候TypeScript会自动校验payload的类型——你必须传入TestPayload<User>类型的payload,确保list是User[],避免类型不匹配的错误。
方式二:通过initialState让TypeScript自动推断泛型
如果你给initialState指定了明确的泛型类型,TypeScript会自动匹配reducer的泛型参数,不用再给useReducer额外加泛型:
比如用AdminUser类型:
interface AdminUser { id: number; name: string; role: 'admin'; } // 直接指定initialState为State<AdminUser> const initialState: State<AdminUser> = { list: [] }; // 这里TypeScript会自动推断reducer的T为AdminUser const [state, dispatch] = useReducer(returnAnyListReducer, initialState);
这种方式更简洁,只要initialState的类型明确,TypeScript就能自动完成泛型推导,省去手动指定泛型的步骤。
为什么之前的代码没生效?
你原来的initialState是{ list: [] },TypeScript会把空数组推断成never[],导致泛型T被推断成never,所以没法正确识别你要传入的User或AdminUser类型。只要显式给initialState指定State<T>类型,或者给useReducer指定泛型,就能解决这个问题。
内容的提问来源于stack exchange,提问作者ShogoTGM

