我有一个使用Component
,connect
并接收自定义属性的React withRouter
。我试图将其转换为TypeScript,我想知道我是否正确地这样做。至少,我现在没有错误。
这是显示概念的代码:
import * as React from 'react'
import { connect } from 'react-redux';
import { withRouter, RouteComponentProps } from 'react-router';
import {
fetchTestLists,
newTestList,
displayTestList,
} from '../../../actions/index';
interface StateProps {
testList: any; // todo: use the type of state.myList to have validation on it
}
interface DispatchProps {
fetchTestLists: () => void;
newTestList: () => void;
displayTestList: (any) => void; // todo: replace any with the actual type
}
interface Props { // custom properties passed to component
className: string;
}
type PropsType = StateProps & DispatchProps & Props;
class MyTest extends React.Component<PropsType & RouteComponentProps<{}>, {}> {
constructor(props) {
super(props);
this.handleCellClick = this.handleCellClick.bind(this);
this.newTestList = this.newTestList.bind(this);
}
componentDidMount() {
this.props.fetchTestLists();
}
handleCellClick(row, column, event) {
this.props.displayTestList(row);
}
newTestList(e) {
this.props.newTestList()
}
render() {
return (
<div className={this.props.className}>
</div>
);
}
}
const mapStateToProps = (state): StateProps => ({
testList: state.myList, // todo: define a type for the root state to have validation here
});
const dispatchToProps = {
fetchTestLists,
newTestList,
displayTestList,
};
export default withRouter<Props & RouteComponentProps<{}>>(connect<StateProps, DispatchProps>(
mapStateToProps,
dispatchToProps,
)(MyTest) as any);
组件的使用方式如下:<MyTest className={"active"} />
我必须做很多实验才能让这个工作。例如:
1)当我省略withRouter的类型时,如下所示:
export default withRouter(connect...
然后我得到TS2339: Property 'className' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Pick<RouteComponentProps<any>, never>, C...'.
这已经在某种程度上被建议:React router in TypeScript- both router and own props,虽然我对这个概念一无所知。
2)如果您想知道最后一行as any
,这与https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18999有关,如果没有它我会收到此错误:
TS2345: Argument of type 'ComponentClass<Pick<any, never>> & { WrappedComponent: ComponentType<any>; }' is not assignable to parameter of type 'ComponentType<Props & RouteComponentProps<{}>>'.
Type 'ComponentClass<Pick<any, never>> & { WrappedComponent: ComponentType<any>; }' is not assignable to type 'StatelessComponent<Props & RouteComponentProps<{}>>'.
Type 'ComponentClass<Pick<any, never>> & { WrappedComponent: ComponentType<any>; }' provides no match for the signature '(props: Props & RouteComponentProps<{}> & { children?: ReactNode; }, context?: any): ReactElement<any> | null'.
这是正确的方法吗?你在哪里看到问题?我基本上使用所有最新版本,这是我的package.json的一个片段:
"react": "^16.2.0",
"redux": "^3.7.2",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "^4.0.8",
...
"typescript": "^2.7.2",
"@types/react-redux": "^5.0.15",
"@types/react-router": "^4.0.22",
"@types/react-router-dom": "^4.2.4",
"@types/react": "^16.0.38",
"@types/react-dom": "^16.0.4",
答案 0 :(得分:6)
我如何在我们的项目中做到这一点(这是最简单的方法,使用时您会获得智能感知):
import * as React from 'react'
import { connect } from 'react-redux';
import { withRouter, RouteComponentProps } from 'react-router';
import {
fetchTestLists,
newTestList,
displayTestList,
} from '../../../actions/index';
interface StateProps {
testList: any; // todo: use the type of state.myList to have validation on it
}
interface DispatchProps {
fetchTestLists: () => void;
newTestList: () => void;
displayTestList: (any) => void; // todo: replace any with the actual type
}
interface Props extends RouteComponentProps { // custom properties passed to component
className: string;
}
type PropsType = StateProps & DispatchProps & Props;
class MyTest extends React.Component<PropsType> {
constructor(props) {
super(props);
this.handleCellClick = this.handleCellClick.bind(this);
this.newTestList = this.newTestList.bind(this);
}
componentDidMount() {
this.props.fetchTestLists();
}
handleCellClick(row, column, event) {
this.props.displayTestList(row);
}
newTestList(e) {
this.props.newTestList()
}
render() {
return (
<div className={this.props.className}>
</div>
);
}
}
const mapStateToProps = (state, ownProps: Props): StateProps => ({
testList: state.myList, // todo: define a type for the root state to have validation here
});
const dispatchToProps: DispatchProps = {
fetchTestLists,
newTestList,
displayTestList,
};
export default withRouter(connect(
mapStateToProps,
dispatchToProps,
)(MyTest));
如果这是您经常键入的内容,我建议您编写一个自定义代码段(如果您使用的是类似VS Code的代码,则非常简单)。
答案 1 :(得分:0)
我尝试重写您的示例,并得到以下代码:
import * as React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps, withRouter } from 'react-router';
import {
fetchTestLists,
newTestList,
displayTestList,
} from '../../../actions/index';
import { Dispatch, bindActionCreators, AnyAction } from 'redux';
interface IStateProps {
testList: IListType; // todo: use the type of state.myList to have validation on it
}
interface IDispatchProps {
fetchTestLists: () => AnyAction;
newTestList: () => AnyAction;
displayTestList: (value: string) => AnyAction; // todo: replace any with the actual type
}
interface IProps { // custom properties passed to component
className: string;
}
type PropsType = IStateProps & IDispatchProps & IProps;
class MyTestComponent extends React.Component<PropsType & RouteComponentProps<{}>, {}> {
constructor(props: PropsType & RouteComponentProps<{}>) {
super(props);
this.handleCellClick = this.handleCellClick.bind(this);
this.newTestList = this.newTestList.bind(this);
}
public componentDidMount() {
this.props.fetchTestLists();
}
public handleCellClick(row, column, event) {
this.props.displayTestList(row);
}
public newTestList(e) {
this.props.newTestList();
}
public render(): JSX.Element {
return (
<div className={this.props.className}>
</div>
);
}
}
export const MyTest = connect(
(state: IAppState, ownProps: IProps) => ({
testList: state.testList,
...ownProps,
}),
(dispatch: Dispatch) => bindActionCreators<AnyAction, Pick<IDispatchProps, keyof IDispatchProps>>(
{ displayTestList, fetchTestLists, newTestList },
dispatch,
),
)(withRouter(MyTestComponent));
interface IListType {
someProp: string;
}
interface IAppState {
testList: IListType;
differentList: IListType;
}
我已将 export default 更改为使用 connect 和 withRouter HOC将包装的 MyTestComponent 类的结果分配给MyTest。然后像这样
导入 MyTest 组件import { MyTest } from './MyTest'
我添加了接口来描述从Parent组件传递来的所有属性,还以不同的方式使用 withRouter 和 connect (对我而言更易理解)。>
我希望这会有所帮助
答案 2 :(得分:-2)
我通过强制安装@ types / react-redux包解决了这个问题。我刚刚从4.4.5更新到5.0.15。
运行新的npm install --save @types/react-redux@5.0.15
可能值得。