如何通过映射类型约束Redux选择器参数并启用TS智能提示?
解决Redux扩展中Selector参数类型推断与命名约束问题
问题分析
你当前的类型定义存在循环约束(Selectors extends SelectorsConstraintMap<Selectors, State>),导致TypeScript无法先推断State类型,再将其传递给Selector的参数,最终参数state被推断为any。而Record<string, Selector<S>>能正常工作,是因为它直接将所有选择器值与State绑定,没有循环依赖。
解决方案
我们需要调整类型定义,先让TypeScript推断State,再约束选择器的键名和参数类型:
1. 定义合法选择器键名约束
用TypeScript模板字符串类型强制选择器名称必须符合selectCapitalCase模式:
type ValidSelectorKey = `select${Capitalize<string>}`;
2. 调整Selector与映射类型
保留Selector的基础定义,同时定义基于State的选择器映射类型,确保每个选择器的参数都绑定到当前State:
type Selector<S, R = any> = (state: S) => R; // 约束选择器集合:键必须符合命名规范,值必须是对应State的Selector type SelectorsForState<S> = { [K in ValidSelectorKey]: Selector<S>; };
3. 重新定义Initializer
让Initializer先推断State,再将State应用到选择器的约束上,避免循环依赖:
type Initializer = <State extends object>(content: { state: State; selectors: SelectorsForState<State>; }) => void; declare const init: Initializer;
使用示例
此时选择器的state参数会自动推断为对应State类型,同时强制命名规范:
init({ state: { x: 123, y: 456 }, selectors: { // state自动推断为{ x: number; y: number },有完整智能提示 selectX: (state) => state.x, selectY: (state) => state.y, // 以下写法会报错:键名不符合selectCapitalCase规范 // foo: (state) => "foo" } });
验证约束
如果尝试给选择器参数指定错误类型,TypeScript会正常报错:
init({ state: { x: 123, y: 456 }, selectors: { // 错误:Type '{ x: number; y: number; }' is not assignable to type 'number'. selectX: (state: number) => state } });
内容的提问来源于stack exchange,提问作者Dellirium
相关产品推荐
相关产品推荐

