使用 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<HomeRouterProps>
?【参考方案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<OwnProps>(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-router
和 react-router-dom
,以及 @types
模块。
我的代码与你基本相同,我的代码使用以下版本:
"@types/react-router-dom": "^4.0.4",
"react-router-dom": "^4.1.1",
【讨论】:
以上是关于使用 TypeScript 的 react-router-dom的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Apollo 和 React Router 避免嵌套路由/查询组件的请求瀑布?