如何从Reducer函数对象推断含键与返回值类型的RootState?
问题描述
我有一个映射Reducer名称与对应Reducer函数的对象:
const reducers = { clients: ClientsReducer, mails: MailsReducer, users: UsersReducer, // ... }
该reducers对象的类型定义如下:
interface Reducers { clients: (state: ClientsState, action: any) => ClientsState, mails: (state: MailsState, action: any) => MailsState, users: (state: UsersState, action: any) => UsersState, // ... }
在应用中使用useSelector选择状态时,需要定义特定的RootState类型:
interface RootState { clients: ClientsState; mails: MailsState; users: UsersState; // ... } // 使用示例 const clients = useSelector((state: RootState) => state.clients);
Redux官方建议通过combineReducers的结果推断该类型:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any; const rootState = combineReducers({ ...reducers }); type RootState = ReturnType<typeof rootState>;
但我的Store是通过不同模块动态创建的,无法获取combineReducers的结果,因此该方法不适用。
我尝试实现的类型如下:
type StateType<T extends Record<S, (...args: any) => any>, S extends string> = T extends Record<S, (...args: any) => infer R> ? Record<S, R> : any; type RootState = StateType<typeof reducers, keyof typeof reducers>; /* * 得到的错误结果: * RootState = { * clients: ClientsState | MailsState | UsersState; * mails: ClientsState | MailsState | UsersState; * users: ClientsState | MailsState | UsersState; * } */
这个结果不正确,每个键对应的类型是所有状态的联合类型。我知道是泛型S导致的问题,但不知道如何修复。
请问是否有方法从reducers对象推断出正确的RootState类型,使其包含对应的键(Reducer名称)和函数返回值(Reducer状态)?
解决方案
可以通过TypeScript的映射类型实现精准的类型推断,逐个处理reducers对象的每个键,提取对应Reducer函数的返回值类型:
方式1:基于已定义的Reducers接口
// 工具类型:提取Reducer函数的返回值类型 type ReducerState<T> = T extends (...args: any[]) => infer R ? R : never; // 遍历Reducers的每个键,映射为对应Reducer的返回值类型 type RootState = { [K in keyof Reducers]: ReducerState<Reducers[K]>; };
方式2:基于typeof reducers直接推断
如果不想依赖预先定义的Reducers接口,也可以直接从reducers对象的类型推断:
type ReducerState<T> = T extends (...args: any[]) => infer R ? R : never; type RootState = { [K in keyof typeof reducers]: ReducerState<(typeof reducers)[K]>; };
原理说明
之前的实现失败是因为泛型S接收的是keyof typeof reducers这个联合类型,Record<S, ...>会将所有键统一映射为所有Reducer返回值的联合类型。而映射类型[K in keyof ...]会逐个遍历每个键,对每个键K单独提取对应Reducer的返回值类型,从而保证每个键与状态类型的一一对应关系。
内容的提问来源于stack exchange,提问作者Gartenzwerg
相关产品推荐
相关产品推荐

