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

如何在TypeScript中正确使用withRouter、connect、React.Component及自定义属性?

我来帮你把这类带connect、withRouter和自定义属性的React组件的TypeScript正确实现理清楚,结合你遇到的TS2339问题,咱们一步步拆解验证你的实现是否靠谱:

正确实现带Redux & Router的React TypeScript组件

这类组件的类型需要覆盖三个核心部分:自定义传入属性、withRouter注入的路由属性、connect注入的Redux状态/方法属性。我们一步步构建符合规范的实现:

1. 先定义所有属性的类型

首先明确你的组件需要接收的所有属性类别:

  • 自定义属性:比如你示例里的className,单独抽成一个接口:
interface MyTestCustomProps {
  className?: string;
  // 其他你需要的自定义属性都放在这里
}
  • 路由属性:不用自己写,直接用react-router-dom提供的RouteComponentProps,它包含了history、location、match这些路由相关属性:
import { RouteComponentProps } from 'react-router-dom';
  • Redux注入属性:如果你的组件通过connect获取Redux的状态或dispatch方法,也要定义对应的类型:
// 假设你有用户状态和一个获取数据的action
interface MyTestReduxProps {
  currentUser: { name: string; id: number };
  fetchUserData: () => void;
}

然后把这三个类型合并成组件的完整属性类型:

type MyTestProps = MyTestCustomProps & RouteComponentProps & MyTestReduxProps;

2. 编写组件本体

组件直接接收合并后的MyTestProps即可,不用额外处理路由或Redux的注入逻辑,因为withRouter和connect会自动把这些属性传进来:

const MyTestComponent: React.FC<MyTestProps> = ({ 
  className, 
  history, 
  currentUser, 
  fetchUserData 
}) => {
  // 组件逻辑示例
  return (
    <div className={className}>
      <p>当前页面路径: {history.location.pathname}</p>
      <p>当前用户: {currentUser.name}</p>
      <button onClick={fetchUserData}>刷新用户数据</button>
    </div>
  );
};

3. 正确包裹connect和withRouter

这里有两个关键注意点:

  • 包裹顺序:必须用withRouter包裹connect的结果,因为connect返回的组件需要withRouter注入路由属性,反过来会导致路由属性被connect过滤掉。
  • connect的泛型参数:一定要给connect指定泛型,明确注入的Redux属性和组件的非Redux属性,避免TypeScript推断错误。

示例代码:

import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';

// 假设你的Redux根状态类型是RootState
const mapStateToProps = (state: RootState) => ({
  currentUser: state.user,
});

const mapDispatchToProps = {
  fetchUserData,
};

// connect的泛型参数依次是:Redux注入的props, 组件接收的非Redux props, Redux根状态类型, 额外dispatch参数
const ConnectedMyTest = connect<MyTestReduxProps, {}, MyTestCustomProps & RouteComponentProps, RootState>(
  mapStateToProps,
  mapDispatchToProps
)(MyTestComponent);

// withRouter不需要额外泛型,它会自动推断组件的属性类型
const MyTest = withRouter(ConnectedMyTest);

export default MyTest;

4. 验证你的实现是否正确

你之前遇到的TS2339错误,正是因为没有把RouteComponentProps合并到组件属性里,导致TypeScript不知道history这类路由属性的存在。现在按照上面的方式定义后,TypeScript能正确识别所有注入的属性,自然不会报错。

而你使用<MyTest className={"active"} />的方式是完全正确的,className属于我们定义的MyTestCustomProps,TypeScript会自动校验这个属性的类型是否符合要求。

常见坑点提醒

  • 别搞反connect和withRouter的包裹顺序,否则路由属性无法正常注入。
  • 不要省略connect的泛型参数,否则TypeScript无法正确推断Redux注入的属性类型,容易出现隐性错误。
  • 一定要把RouteComponentProps合并到组件的属性类型里,不然用到路由相关属性时就会触发TS2339错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:33:02