使用 TypeScript 的 react-router-dom

Posted

技术标签:

【中文标题】使用 TypeScript 的 react-router-dom【英文标题】:react-router-dom with TypeScript 【发布时间】:2017-10-22 10:01:54 【问题描述】:

我正在尝试将 react 路由器与 TypeScript 一起使用。但是,我在使用 withRouter 函数时遇到了一些问题。在最后一行,我遇到了非常奇怪的错误:

Argument of type 'ComponentClass<>' is not assignable to parameter of type 'StatelessComponent<RouteComponentProps<any>> | ComponentClass<RouteComponentProps<any>>'.
  Type 'ComponentClass<>' is not assignable to type 'ComponentClass<RouteComponentProps<any>>'.
    Type '' is not assignable to type 'RouteComponentProps<any>'.
      Property 'match' is missing in type '’

代码如下:

import * as React from 'react';
import  connect  from 'react-redux';
import  RouteComponentProps, withRouter  from 'react-router-dom';

interface HomeProps extends RouteComponentProps<any> 


interface HomeState  

class Home extends React.Component<HomeProps, HomeState> 
  constructor(props: HomeProps) 
    super(props);
  
  public render(): JSX.Element 
    return (<span>Home</span>);
  


const connectModule = connect(
  (state) => (
    // Map state to props
  ),
  
    // Map dispatch to props
  )(Home);

export default withRouter(connectModule);

【问题讨论】:

【参考方案1】:

我是怎么做的:

interface IOwnProps 
  style?: CSSProperties;


interface INavProps 
  item?: string;


type IProps = IOwnProps & RouteComponentProps<INavProps>;

export default class MapScreen extends PureComponent<IProps> 
  ...

【讨论】:

【参考方案2】:

我使用不同的方法来解决这个问题。我总是将不同的属性(路由器、常规和调度)分开,所以我为我的组件定义了以下接口:

interface HomeRouterProps 
  title: string;   // This one is coming from the router


interface HomeProps extends RouteComponentProps<HomeRouterProps> 
  // Add your regular properties here


interface HomeDispatchProps 
  // Add your dispatcher properties here

您现在可以创建一个新类型,将所有属性组合在一个类型中,但我总是在组件定义期间组合类型(我不在这里添加状态,但如果您需要,请继续)。组件定义如下所示:

class Home extends React.Component<HomeProps & HomeDispatchProps> 
  constructor(props: HomeProps & HomeDispatchProps) 
    super(props);
  

  public render() 
    return (<span>this.props.match.params.title</span>);
  

现在我们需要通过容器将组件连接到状态。它看起来像这样:

function mapStateToProps(state, ownProps: HomeProps): HomeProps => 
  // Map state to props (add the properties after the spread)
  return  ...ownProps ;


function mapDispatchToProps(dispatch): HomeDispatchProps 
  // Map dispatch to props
  return ;


export default connect(mapStateToProps, mapDispatchToProps)(Hello);

此方法允许完全类型化的连接,因此组件和容器是完全类型化的,并且可以安全地对其进行重构。唯一对重构不安全的是路由中映射到HomeRouterProps 接口的参数。

【讨论】:

你在哪里给withRouter打电话? 赞成。这确实是解决问题的“正确”方法。如果您使用的是 TypeScript,请正确输入您的组件! 现在,这大约有一年了,但 HelloDispatchProps 不应该是 HomeDispatchProps 吗? mapStateToProps 中,不应该是ownProps 类型的RouteComponentProps&lt;HomeRouterProps&gt;【参考方案3】:

浏览 typescript 定义后,我发现了 RouteComponentProps 接口,所以我现在像这样对容器进行建模

type RouteParams = 
    teamId: string; // must be type string since route params


interface Props extends RouteComponentProps<RouteParams>, React.Props<RouteParams>  

type State = 
    players: Array<Player>;


export class PlayersContainer extends React.Component<Props, State> 

现在在组件类中,可以像这样访问路由道具: let teamid = this.props.match.params.teamId;

【讨论】:

【参考方案4】:

+1 表示 Ramon 的回答。您绝对可以在这里获得完整的类型覆盖。补充一点 - 我添加了对 withRouter 的调用。

interface FooProps extends RouteComponentProps<Foo> 
  foo: string;


const Foo = ( history, foo : FooProps) => <span/>;

const RoutedFoo = withRouter(Foo);

我的依赖:

"@types/react-router-dom": "^4.3.0",
"typescript": "^2.9.2",

【讨论】:

【参考方案5】:

这是一个打字稿打字问题。由于 withRouter() 将在运行时提供你需要的路由道具,你想告诉消费者他们只需要指定 other 道具。在这种情况下,您可以只使用普通的 ComponentClass:

export default withRouter(connectModule) as React.ComponentClass<>;

或者,如果您想要传入其他道具(在名为 OwnProps 的接口中定义),您可以这样做:

export default withRouter(connectModule) as React.ComponentClass<OwnProps>;

讨论有点多here

【讨论】:

withRouter 使用泛型,因此您可以键入而不是类型转换:export default withRouter&lt;OwnProps&gt;(connectModule);【参考方案6】:

我认为这是打字稿打字编译问题,但我找到了解决方法:

interface HomeProps extends RouteComponentProps<any>, React.Props<any> 

【讨论】:

我更愿意将此标记为预期行为。 Kevin Welcher 在这里概述了为什么需要更多:medium.com/@kaw2k/a-letter-of-appreciation-253ecab3f7d2 在类型上声明 any 会首先消除使用类型的目的。方法错误。 是的,这不是正确的方法,这就是我将其归类为解决方法的原因。【参考方案7】:

看起来你有正确的用法将匹配、历史和位置道具应用到你的组件。我会检查你的 node_modules 目录,看看你有哪些版本的 react-routerreact-router-dom,以及 @types 模块。

我的代码与你基本相同,我的代码使用以下版本:


  "@types/react-router-dom": "^4.0.4",
  "react-router-dom": "^4.1.1",

【讨论】:

以上是关于使用 TypeScript 的 react-router-dom的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Apollo 和 React Router 避免嵌套路由/查询组件的请求瀑布?

如何使用 react-router 重定向到另一条路由?

React Router 4 异步渲染

typescript使用 TypeScript 开发 Vue 组件

React学习:react-router-dom-主要组件

使用来自使用旧版 Typescript 确定类型的 Typescript 定义文件