我有以下堆栈:
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组件?答案 0 :(得分:1)
如果您开始将鼠标悬停在一些道具上,就会发现有很多never
正在进行。
道具是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
。
推断的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>
我希望我的types
和interfaces
独立于我的代码,所以我不喜欢typeof connector
。我们知道要从redux中提取哪些道具,因此我们可以直接输入它们。
type PropsFromRedux = {
foo: number;
dispatch: Dispatch;
}