You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript下Redux选择器抽象层级及类型推导可行性问询

Redux + TypeScript 选择器复用与类型推导实现方案

问题场景

原本使用Redux connect结合TypeScript的标准实现能正常推导props类型,但抽离选择器复用后,自定义的mapStateToProps包装函数无法让TypeScript正确推导mapState返回的props类型,导致ConnectedProps只能识别actions的类型。

原标准实现

import { connect, ConnectedProps } from 'react-redux'

interface RootState {
  isOn: boolean
}

const mapState = (state: RootState) => ({
  isOn: state.isOn,
})

const mapDispatch = {
  toggleOn: () => ({ type: 'TOGGLE_IS_ON' }),
}

const connector = connect(mapState, mapDispatch)

// 能正确推导类型:{isOn: boolean, toggleOn: () => void}
type PropsFromRedux = ConnectedProps<typeof connector>

抽离选择器后的尝试

// selectors.js
const selector1 = (state) => state.attr1;
const selector2 = (state) => state.attr2;
const selector3 = (state) => state.attr3;
import {selector1,selector3} from '../../selectors';    

const selectors = {
    attr1:selector1,
    attr3:selector3,
}

// 自定义的mapState生成函数,但类型丢失
const mapStateToProps = (selectors: Selectors) => {
  return Object.keys(selectors).reduce((acc, selectorKey) => {
    acc[selectorKey] = selectors[selectorKey](state);
    return acc;
  }, {});
};

// 生成的connector无法推导mapState的props类型
const connector = connect(mapStateToProps(selectors), actions)
type PropsFromRedux = ConnectedProps<typeof connector> // 仅能获取actions类型

可行方案与类型推导实现

这个复用选择器的方案完全可行,核心是通过泛型约束让TypeScript捕获选择器与最终props的类型关联,具体实现步骤如下:

1. 给选择器添加TypeScript类型

首先将selectors.js改为selectors.ts,并关联RootState类型:

// selectors.ts
import { RootState } from './path-to-your-root-state'; // 导入全局RootState类型

export const selector1 = (state: RootState) => state.attr1;
export const selector2 = (state: RootState) => state.attr2;
export const selector3 = (state: RootState) => state.attr3;

2. 编写带泛型的mapState生成函数

通过泛型捕获选择器对象的键与返回值类型,确保生成的mapState函数有明确的类型标注:

import { RootState } from './path-to-your-root-state';

// 定义选择器映射的泛型类型:键对应最终props的键,值是接收RootState返回对应值的选择器
type SelectorMap<Props> = {
  [Key in keyof Props]: (state: RootState) => Props[Key];
};

// 生成mapState的函数,泛型P代表最终要映射到组件的props类型
const createMapState = <P>(selectors: SelectorMap<P>) => {
  return (state: RootState): P => {
    return Object.keys(selectors).reduce((acc, key) => {
      acc[key as keyof P] = selectors[key as keyof P](state);
      return acc;
    }, {} as P);
  };
};

3. 生成带类型的mapState并连接组件

使用createMapState生成mapState,此时TypeScript能完整推导mapState的返回类型,ConnectedProps也能获取完整的props类型:

import { connect, ConnectedProps } from 'react-redux';
import { selector1, selector3 } from './selectors';
import { toggleOn } from './your-actions-file'; // 确保actions有类型定义

// 定义选择器映射对象
const selectors = {
  attr1: selector1,
  attr3: selector3,
};

// 生成带完整类型的mapState
const mapState = createMapState(selectors);

// mapDispatch可以是对象或函数(此处用对象示例)
const mapDispatch = {
  toggleOn,
};

// 创建连接器
const connector = connect(mapState, mapDispatch);

// 此时能正确推导完整类型:{attr1: typeof selector1返回值, attr3: typeof selector3返回值, toggleOn: typeof toggleOn}
type PropsFromRedux = ConnectedProps<typeof connector>;

关键原理说明

原来的实现中,mapStateToProps直接调用后返回的是无类型标注的普通对象,TypeScript无法识别其与选择器的关联。而带泛型的createMapState通过泛型P捕获了选择器对象对应的props结构,返回的mapState函数明确标注了返回类型P,让connect能正确识别mapState的输出类型,最终ConnectedProps可以合并mapState和mapDispatch的完整类型。

内容的提问来源于stack exchange,提问作者JmRag

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 01:00:59