Javascript 是否在TypeScript中包装函数的嵌套对象?
我正在使用Redux,并已将存储数据分解为“切片”。每个“切片”对应一个区域,例如Javascript 是否在TypeScript中包装函数的嵌套对象?,javascript,typescript,redux,Javascript,Typescript,Redux,我正在使用Redux,并已将存储数据分解为“切片”。每个“切片”对应一个区域,例如用户或注释。我将每个切片的选择器组合成一个顶级的选择器模块,我可以在整个应用程序中访问该模块 切片的格式如下: export interface IUsersSelectors { getCurrentUser(state: IUsersState): IUser | undefined; } const selectors: IUsersSelectors = { getCurrentUser(stat
用户
或注释
。我将每个切片的选择器组合成一个顶级的选择器
模块,我可以在整个应用程序中访问该模块
切片的格式如下:
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>...
但是,在尝试将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[]
),只覆盖第一个参数作为全局存储状态
有没有更好的方法来处理这样的嵌套泛型?这可能吗?您需要为
IScopedSelectors
和INestedScopedSelectors
的泛型类型添加类似的类型约束
如果没有这样的约束,您已经告诉TypeScript,IScopedSelectors
中的T
可以是任何类型。因此,IScopedSelectors
应该是有效的。但是TypeScript正确地指出,对于许多类型(例如string
),[K in keyof T]:IScopedSelector
不起作用,因为无法保证T[K]
遵守IScopedSelector
施加的约束
因此,解决方案只是向两个接口添加一个约束,这样TypeScript就有了这个保证。为此,内置的记录
类型可能会有所帮助。比如:
type IScopedSelectors<T extends Record<string, () => any>> = {
[K in keyof T]: IScopedSelector<T[K]>; // T[K] is now guaranteed to adhere to () => any
};
type INestedScopedSelectors<R extends Record<string, Record<string, () => any>>> = {
[S in keyof R]: IScopedSelectors<R[S]>; // Similarly, R[S] is now guaranteed to adhere to Record<string, () => any>, exactly what IScopedSelectors is expecting.
};
类型IScopedSelectors>={
[K in keyof T]:IScopedSelector;//T[K]现在保证遵守()=>any
};
输入INestedScopedSelectors>={
[S in keyof R]:IScopedSelectors;//类似地,R[S]现在保证遵守Record any>,这正是IScopedSelectors所期望的。
};
根据具体的用例,您可能希望用更具体的内容替换记录
类型,但解决方案基本相同。只需确保将约束一直向前推进到层次结构
希望有帮助 谢谢你的回复!我认为这在理论上是有道理的。但是,当我尝试将
ISelectors
接口传递给InestdScopedSelectors
时,会出现一个错误:类型“ISelectors”不满足约束“Record>”。类型“ISelectors”中缺少索引签名。
我想我需要ISelectors
中某个位置的记录
类型,但不确定该类型是什么样子,因为该接口只是一个简单的映射?您可以通过使用内联映射类型来消除对索引签名的需要。所以T分别扩展了{[K in keyof T]:()=>any}
和R分别扩展了{[S in keyof R]:{[K in keyof R[S]:()=>any}
。但是typescript指出了另一个问题,即:属性“getCurrentUser”的类型不兼容,类型(state:IUsersState)=>IUser |未定义的
不可分配给()=>任何
。您可以通过使用(…args:any[])=>any
而不是()=>any
来解决这个问题,但是我不确定对于您的用例来说,这种类型是否太允许。真见效了!在globalState
之后,我确实丢失了所有参数的键入,但是除非您有任何解决方法,否则这仍然比根本不键入要好得多。谢谢
type IScopedSelectors<T extends Record<string, () => any>> = {
[K in keyof T]: IScopedSelector<T[K]>; // T[K] is now guaranteed to adhere to () => any
};
type INestedScopedSelectors<R extends Record<string, Record<string, () => any>>> = {
[S in keyof R]: IScopedSelectors<R[S]>; // Similarly, R[S] is now guaranteed to adhere to Record<string, () => any>, exactly what IScopedSelectors is expecting.
};