输入一个同时使用 withRouter 和 connect 的 HOC 组件
Posted
技术标签:
【中文标题】输入一个同时使用 withRouter 和 connect 的 HOC 组件【英文标题】:typing a HOC component that's using both withRouter and connect 【发布时间】:2020-10-31 04:01:35 【问题描述】:我有以下堆栈:
react@16.13.1
react-dom@16.13.1
react-redux@7.2.0
react-router-dom@5.2.0
我按照this answer 中建议的方法对使用withRouter
创建的HOC 组件进行类型检查,并且工作正常。例如。以下组件类型检查:
import React from "react";
import withRouter from "react-router-dom";
import RouteComponentProps from "react-router-dom";
type Props = RouteComponentProps<any>;
class Test extends React.Component<Props, >
componentDidMount = () =>
this.props.history.push("foo");
;
render()
return <div>foo</div>;
export default withRouter(Test);
当我还希望使用connect
将组件链接到 Redux 存储时,就会出现问题。以下代码无法进行类型检查:
import React from "react";
import connect, ConnectedProps from "react-redux";
import withRouter from "react-router-dom";
import RouteComponentProps from "react-router-dom";
type RootState = foo: number ;
const mapStateToProps = (state: RootState) =>
foo: state.foo;
;
const connector = connect(mapStateToProps, null);
type PropsFromRedux = ConnectedProps<typeof connector>;
type Props = PropsFromRedux & RouteComponentProps<any>;
class Test extends React.Component<Props, >
componentDidMount = () =>
this.props.history.push("foo"); // TS2339: Property 'history' does not exist on type 'never'.
;
render()
return <div>foo</div>;
export default withRouter(connector(Test));
具体来说,我得到:
TS2339: Property 'history' does not exist on type 'never'.
两个问题:
-
为什么
props
的类型被评估为never
?
如何正确检查使用withRouter
和connect
连续应用创建的HOC 组件?
【问题讨论】:
PropsFromRedux
和 RouteComponentProps
都没有提到history
?
@user0101 如果是这种情况,那么第一个代码清单也不会进行类型检查。因此,RouteComponentProps
确实声明了history
。但不知何故,当RouteComponentProps
类型与ConnectedProps
的输出相结合时,我们就会遇到我无法解释的类型检查问题。
【参考方案1】:
从不
如果您开始将鼠标悬停在一些道具上,您会看到有很多 never
正在进行。
Props 是 never
,因为 PropsFromRedux
是 never
(never
的并集总是 never
)。
type ConnectedProps<TConnector> = TConnector extends InferableComponentEnhancerWithProps<infer TInjectedProps, any> ? TInjectedProps : never
如上所示,ConnectedProps
实用程序类型返回InferableComponentEnhancerWithProps
的第一个泛型。
PropsFromRedux
,即ConnectedProps<typeof connector>
,计算结果为never
,因为connected
的类型是InferableComponentEnhancerWithProps<never, >
。
所以向后追溯,我们看到核心问题是connected
的类型。
无效
您实际上在 mapStateToProps
函数中犯了一个错误,因为您忘记将它括在括号中,所以您实际上并没有返回任何内容!仅此一项并不能解决您的问题(它只是将 never
替换为 void
),但它是其他修复的先决条件。
const mapStateToProps = (state: RootState) => (
foo: state.foo;
);
现在它返回 foo: number
而不是 void
。
解决方案 1
connected
的推断类型出错的原因是您将dispatch
参数设置为null
。 connect
函数有 14 different overloads,但唯一允许第二个参数为 null
的是设置第三或第四个参数的那些。如果您不需要设置第二个 dispatch
参数,则应该完全不使用它。
当我们去掉 null
参数时,突然一切都好了,this.props.history
得到类型 History<any>
。
const connector = connect(mapStateToProps);
// => InferableComponentEnhancerWithProps<foo: number & DispatchProp<AnyAction>, >
type PropsFromRedux = ConnectedProps<typeof connector>;
// => foo: number & DispatchProp<AnyAction>
type Props = PropsFromRedux & RouteComponentProps<any>;
// => foo: number & DispatchProp<AnyAction> & RouteComponentProps<any, StaticContext, any>
解决方案 2
我喜欢我的types
和interfaces
独立于我的代码,所以我不喜欢typeof connector
。我们知道我们想从 redux 中提取什么 props,所以我们可以直接输入它们。
type PropsFromRedux =
foo: number;
dispatch: Dispatch;
Typescript Playground Link
【讨论】:
以上是关于输入一个同时使用 withRouter 和 connect 的 HOC 组件的主要内容,如果未能解决你的问题,请参考以下文章
使用“withRouter”和 Typescript 时出现类型问题
React Context API + withRouter - 我们可以一起使用它们吗?
测试包含在 withRouter 中的反应组件(最好使用 jest/enzyme)
在 react 中使用 react-router 4 和 styled-component 时,不应在 Router 外部使用 Route 或 withRouter()