TypeScript 2.8:简化类型安全Reducer遇信息丢失问题求助
解决Redux Action类型信息丢失问题:结合手动接口与ReturnType推导
我懂你遇到的痛点——尝试用ReturnType<A[keyof A]>简化Redux Reducer的类型定义时,手动创建的Action接口(比如MyFirstAction、MySecondAction)总是会丢失属性信息,导致Reducer里没法正确识别Action的额外字段对吧?这其实是因为手动接口和action creator的返回类型没有建立强关联,让TypeScript没法正确映射两者的关系。下面给你两种可行的解决方案:
方案一:让Action Creator严格关联手动定义的接口
如果你还是想保留手动定义的Action接口(比如需要在其他地方复用这些接口),只需要确保每个action creator的返回类型明确指向对应的接口,而不是让TypeScript自动推导:
import { Action } from 'redux'; // 枚举Action类型 enum MyEnum { FirstAction = 'FIRST_ACTION', SecondAction = 'SECOND_ACTION' } // 手动定义Action接口 export interface MyFirstAction extends Action<MyEnum.FirstAction> { someProperty: string; } export interface MySecondAction extends Action<MyEnum.SecondAction> { numProperty: number; } // 让action creator的返回类型严格对应接口 const myFirstAction = (payload: string): MyFirstAction => ({ type: MyEnum.FirstAction, someProperty: payload }); const mySecondAction = (payload: number): MySecondAction => ({ type: MyEnum.SecondAction, numProperty: payload }); // 把所有action creator整合到一个对象 const actionCreators = { myFirstAction, mySecondAction }; // 推导完整的Action类型集合 type AppActions = ReturnType<typeof actionCreators[keyof typeof actionCreators]>;
这样AppActions就会准确包含MyFirstAction和MySecondAction的所有类型信息,Reducer里使用这个类型时,每个case分支的Action属性都会被正确识别。
方案二:完全通过Action Creator推导Action类型(更简洁)
如果不需要单独复用Action接口,推荐直接通过action creator的返回值来推导所有Action类型,这样从根源上避免信息丢失,代码也更简洁:
import { Action } from 'redux'; enum MyEnum { FirstAction = 'FIRST_ACTION', SecondAction = 'SECOND_ACTION' } // 直接定义action creators,不用手动写接口 const myFirstAction = (someProperty: string) => ({ type: MyEnum.FirstAction, someProperty }); const mySecondAction = (numProperty: number) => ({ type: MyEnum.SecondAction, numProperty }); const actionCreators = { myFirstAction, mySecondAction }; // 自动推导所有Action类型 type AppActions = ReturnType<typeof actionCreators[keyof typeof actionCreators]>;
在Reducer中使用推导后的类型
不管用哪种方案,Reducer里的类型都会完美工作:
type AppState = { someValue?: string; numValue?: number; }; const initialState: AppState = {}; const reducer = (state: AppState = initialState, action: AppActions): AppState => { switch (action.type) { case MyEnum.FirstAction: // 这里action.someProperty会被正确推断为string类型 return { ...state, someValue: action.someProperty }; case MyEnum.SecondAction: // action.numProperty会被正确推断为number类型 return { ...state, numValue: action.numProperty }; default: return state; } };
关键注意点
- 如果你坚持手动定义Action接口,不要省略action creator的返回类型标注——让TypeScript自动推导返回类型的话,可能会和手动接口产生细微差异,导致类型信息丢失。
- 用
typeof actionCreators[keyof typeof actionCreators]遍历所有action creator,确保不会漏掉任何一个Action类型,也避免了手动维护Action联合类型的麻烦。
内容的提问来源于stack exchange,提问作者Erik Živković
相关产品推荐
相关产品推荐

