如何为Action Creator与Reducer的元组数组做TypeScript类型校验?
类型校验Action Creator与Reducer元组数组的实现方案
需求明确
- 校验Action Creator生成的Action的Payload,与对应Reducer接收的Payload完全一致
- 确保所有Reducer接收的State类型统一
- 实现方案需与状态管理库无关,且无需手动维护有效Payload列表
现有方案问题
- 函数创建元组:该方式能实现校验,但依赖函数调用生成元组,希望直接用纯数据结构(如数组字面量)完成定义
- 简单类型助手:无法正确识别Action与Reducer的错误配对,类型校验失效
解决方案实现
1. 基础类型定义
先明确State、Action、Action Creator、Reducer的基础类型:
// 全局统一的State类型 type AppState = { count: number; name: string }; // Action基础结构 type Action<Type extends string, Payload = void> = { type: Type; payload?: Payload; }; // Action Creator类型:返回对应类型的Action type ActionFn<Type extends string, Payload = void> = Payload extends void ? () => Action<Type> : (payload: Payload) => Action<Type, Payload>; // Reducer类型:接收统一State和对应Action,返回新State type Reducer<Payload = void> = ( state: AppState, action: Action<string, Payload> ) => AppState;
2. 核心类型校验助手
定义类型工具,强制单个元组中的Action Creator与Reducer的Payload匹配:
// 提取Action Creator的Payload类型 type ExtractActionPayload<Fn> = Fn extends ActionFn<string, infer P> ? P : never; // 校验单个[ActionCreator, Reducer]元组的合法性 type ValidActionReducerPair<T> = T extends [ActionFn<string, infer P>, Reducer<P>] ? T : never; // 校验整个数组的所有元组都符合规则 type ValidActionReducerArray = Array<ValidActionReducerPair<[ActionFn, Reducer]>>;
3. 实际使用示例
正确配对示例
// 定义符合规则的Action Creator和Reducer const actionA: ActionFn<'INCREMENT', number> = (payload) => ({ type: 'INCREMENT', payload }); const reducerA: Reducer<number> = (state, action) => ({ ...state, count: state.count + action.payload! }); const actionB: ActionFn<'SET_NAME', string> = (payload) => ({ type: 'SET_NAME', payload }); const reducerB: Reducer<string> = (state, action) => ({ ...state, name: action.payload! }); // 合法的元组数组:类型校验通过 const validPairs: ValidActionReducerArray = [ [actionA, reducerA], [actionB, reducerB] ];
错误配对示例
// 错误配对:Action的Payload是number,Reducer期望string const invalidPairs: ValidActionReducerArray = [ [actionA, reducerB] // 类型报错:元组类型不匹配 ];
方案说明
- 利用TypeScript的条件类型和类型推断,自动提取Action Creator的Payload类型,与Reducer的Payload类型做强制匹配
- 无需手动维护Payload列表,所有类型推导完全基于Action Creator和Reducer的定义
- 纯数据结构(数组字面量)定义元组数组,同时保留严格的类型校验
内容的提问来源于stack exchange,提问作者sindre
相关产品推荐
相关产品推荐

