Reactjs 用TypeScript响应路由器dom

Reactjs 用TypeScript响应路由器dom,reactjs,typescript,react-router,react-router-v4,react-router-redux,Reactjs,Typescript,React Router,React Router V4,React Router Redux,我正在尝试将react路由器与TypeScript一起使用。但是,我在使用withRouter函数时遇到了一些问题。在最后一行,我得到了一个非常奇怪的错误: Argument of type 'ComponentClass<{}>' is not assignable to parameter of type 'StatelessComponent<RouteComponentProps<any>> | ComponentClass<RouteCompo

我正在尝试将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 '{}’
类型为“ComponentClass”的参数不能分配给类型为“无状态组件| ComponentClass”的参数。
类型“ComponentClass”不可分配给类型“ComponentClass”。
类型“{}”不可分配给类型“RouteComponentProps”。
类型“{}”中缺少属性“match”
代码如下所示:

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);
import*as React from'React';
从'react redux'导入{connect};
从“react router dom”导入{RouteComponentProps,withRouter};
接口HomeProps扩展了RouteComponentProps{
}
接口主状态{}
类Home扩展了React.Component{
构造器(道具:家庭道具){
超级(道具);
}
public render():JSX.Element{
返回(家);
}
}
const connectModule=connect(
(州)=>({
//将状态映射到道具
}),
{
//地图发送到道具
})(家);
使用路由器导出默认值(连接模块);

看起来您有正确的用法将匹配、历史记录和位置道具应用于组件。我将检查您的
节点\u模块
目录,查看您拥有的
反应路由器
反应路由器dom
的版本,以及
@类型
模块

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

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

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

interface HomeProps extends RouteComponentProps<any>, React.Props<any> {
}
接口HomeProps扩展了RouteComponentProps、React.Props{
}

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

export default withRouter(connectModule) as React.ComponentClass<{}>;
将路由器(connectModule)的默认值导出为React.ComponentClass;
或者,如果您想传入其他道具(在名为OwnProps的接口中定义),您可以这样做:

export default withRouter(connectModule) as React.ComponentClass<OwnProps>;
将路由器(connectModule)的默认值导出为React.ComponentClass;

还有更多的讨论

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

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
}

此方法允许全类型连接,因此组件和容器是全类型的,重构它是安全的。对于重构来说,唯一不安全的是路由中映射到
HomeRouterProps
接口的参数。

+1获取Ramon的答案。你完全可以在这里得到全类型的保险。为了增加一点,我将呼叫添加到withRouter

interface FooProps extends RouteComponentProps<Foo> {
  foo: string;
}

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

const RoutedFoo = withRouter(Foo);

在浏览了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>{} 
类型路由图={
teamId:string;//必须是string类型,因为路由参数
}
接口Props扩展了RouteComponentProps,React.Props{}
类型状态={
玩家:阵型;
}
导出类PlayerContainer扩展React.Component{}
现在,在component类中,可以按如下方式访问路由道具:
让teamid=this.props.match.params.teamid

我是如何做到这一点的:

interface IOwnProps {
  style?: CSSProperties;
}

interface INavProps {
  item?: string;
}

type IProps = IOwnProps & RouteComponentProps<INavProps>;

export default class MapScreen extends PureComponent<IProps> {
  ...
}
接口IOwnProps{
风格?:CSSProperties;
}
INavProps接口{
项目?:字符串;
}
IProps类型=IOwnProps和RouteComponentProps;
导出默认类MapScreen扩展PureComponent{
...
}

withRouter
使用泛型,因此您可以键入它而不是类型转换:
导出默认withRouter(connectModule)。我更愿意将此标记为预期行为。凯文·韦尔彻(Kevin Welcher)在这里概述了为什么需要更多一点:在打字时声明任何内容都会从一开始就消除使用打字的目的。错误的方法。是的,这不是正确的方法,这就是为什么我将其归类为变通方法。您对路由器的调用在哪里?向上投票。这确实是解决问题的“正确”方法。如果您使用的是TypeScript,请正确键入您的组件!现在,这大约有一年了,但是
HelloDispatchProps
不应该是
HomeDispatchProps
?在
MapStateTrops
中,不应该是
ownProps
类型的
RouteComponentProps
"@types/react-router-dom": "^4.3.0",
"typescript": "^2.9.2",
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>{} 
interface IOwnProps {
  style?: CSSProperties;
}

interface INavProps {
  item?: string;
}

type IProps = IOwnProps & RouteComponentProps<INavProps>;

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