Redux Toolkit中实现选择器全局化及正确类型定义
问题
在Redux Toolkit的slice文件中,我创建了如下局部选择器:
const getSomething = (state: TreeState) => simpleOperations(state.something)
该选择器返回number类型,我会在reducer中复用它以避免代码重复。现在我希望将这些选择器导出到组件中使用,目前的写法是:
const something = useSelector(state => getSomething(state.tree))
(假设全局状态RootState包含类型为TreeState的子状态tree)
我希望简化为:
const something = useSelector(getSomething)
因此我计划将getSomething设为slice内私有,通过工具函数globalizeSelectors将所有局部选择器包装为全局选择器并导出。我期望局部选择器(state: TreeState) => number能被包装为签名为(state: RootState) => number的全局选择器,且返回类型一致。
我当前的实现如下:
const getSomething = (state: TreeState) => simpleOperations(state.something) function globalizeSelectors<T extends {}>(subStateSelector: (state: RootState) => T, selectors: { [key: string]: (subState: T) => any }) { const globalized: { [key: keyof typeof selectors]: (state: RootState) => any } = {} for (let selector in selectors) globalized[selector] = (state: RootState) => selectors[selector](subStateSelector(state)) return globalized } export const treeSelectors = globalizeSelectors<TreeState>(state => state.tree, {getSomething})
组件中的使用示例:
const something = useSelector(treeSelectors.getSomething)
我需要TypeScript能正确推断:
treeSelectors包含getSomething属性getSomething的签名为(state: RootState) => numbersomething为number类型- 支持任意数量、任意返回类型的局部选择器
但当前实现无法让TypeScript正确推断类型,请问该如何修改?globalizeSelectors可完全重写。
解决方案
要让TypeScript正确推断所有类型,需要细化globalizeSelectors的泛型定义,捕获每个局部选择器的精确类型信息,而非用any模糊处理。
修改后的工具函数实现如下:
// 泛型S:局部状态类型;泛型T:传入的选择器对象的精确类型 function globalizeSelectors<S, T extends Record<string, (state: S) => unknown>>( subStateSelector: (state: RootState) => S, selectors: T ): { [K in keyof T]: (state: RootState) => ReturnType<T[K]> } { const globalized: Record<string, unknown> = {} for (const key in selectors) { if (Object.prototype.hasOwnProperty.call(selectors, key)) { globalized[key] = (state: RootState) => selectors[key](subStateSelector(state)) } } return globalized as { [K in keyof T]: (state: RootState) => ReturnType<T[K]> } }
在slice中使用的示例:
// 局部选择器保持私有 const getSomething = (state: TreeState) => simpleOperations(state.something) const getAnotherThing = (state: TreeState) => state.anotherValue // 示例:返回string类型 // 导出全局选择器 export const treeSelectors = globalizeSelectors(state => state.tree, { getSomething, getAnotherThing })
关键修改说明
- 精确泛型捕获:用泛型
T捕获传入的选择器对象的完整类型,包括每个选择器的键名和返回值类型,避免索引类型的模糊性。 - 返回类型映射:通过
{ [K in keyof T]: (state: RootState) => ReturnType<T[K]> },将每个局部选择器的类型映射为接收全局RootState、返回相同结果类型的全局选择器。 - 安全类型断言:遍历构建后的对象结构完全符合映射后的类型,因此用类型断言完成转换,避免不必要的类型错误。
组件中的类型推断效果
// TypeScript自动推断something为number类型 const something = useSelector(treeSelectors.getSomething) // TypeScript自动推断anotherThing为string类型 const anotherThing = useSelector(treeSelectors.getAnotherThing)
该实现完全满足需求:自动识别选择器属性、正确的函数签名、精确的返回类型,同时支持任意数量和返回类型的局部选择器。
内容的提问来源于stack exchange,提问作者edoedoedo
相关产品推荐
相关产品推荐

