【发布时间】:2018-05-23 00:27:29
【问题描述】:
我正在使用 Redux 并将存储数据分解为“切片”。每个“切片”对应一个区域,例如users 或comments。我将每个切片的选择器组合成一个顶级 selectors 模块,我可以在整个应用程序中访问该模块。
切片的格式为:
export interface IUsersSelectors {
getCurrentUser(state: IUsersState): IUser | undefined;
}
const selectors: IUsersSelectors = {
getCurrentUser(state: IUsersState) {
return state.currentUser;
}
};
export default {
getInitialState,
reducer,
selectors
};
然后将其全部导入,并组合选择器:
export const selectors = Object.keys(slices).reduce((combinedSelectors: any, sliceKey: string) => {
const sliceSelectors = slices[sliceKey].selectors;
combinedSelectors[sliceKey] = Object.keys(sliceSelectors).reduce((selectorsMap: object, selectorKey: string) => {
const localizedSelector = sliceSelectors[selectorKey];
selectorsMap[selectorKey] = (globalState, ...args: any[]): any => {
return localizedSelector(globalState[sliceKey], ...args);
};
return selectorsMap;
}, {});
return combinedSelectors;
}, {});
然后在整个应用程序中使用:
selectors.users.getCurrentUser(store.getState());
这意味着选择器在检索数据时期望只是它们的切片状态,但它们实际上是调用全局存储状态的。我基本上只是将它们包装在另一个管理范围的函数中。
我最接近为此定义泛型类型的是:
type IScopedSelector<T extends () => any> = (globalState: IStoreState, ...args: any[]) => ReturnType<T>;
type IScopedSelectors<T> = {
[K in keyof T]: IScopedSelector<T[K]>;
};
type INestedScopedSelectors<R> = {
[S in keyof R]: IScopedSelectors<R[S]>;
};
export const selectors: INestedScopedSelectors<ISelectors>...
其中ISelectors是形状的简单界面:
export interface ISelectors {
users: IUsersSelectors;
}
但是,当我尝试将 T[K] 传递给 IScopedSelector 时,我收到了一个错误,因为它必须是一个函数:
[ts] Type 'T[K]' does not satisfy the constraint '() => any'.
如果我删除 extends () => any,则会收到关于 ReturnType 的错误:
[ts] Type 'T' does not satisfy the constraint '(...args: any[]) => any'.
理想情况下,我也会保持选择器参数的类型(而不是 ...args: any[]),仅将第一个参数覆盖为全局存储状态。
有没有更好的方法来处理这样的嵌套泛型?这甚至可能吗?
【问题讨论】:
标签: javascript typescript redux