React Router - ошибки Typescript onRouter после обновления версии
Я просто попытался обновить приложение React до
response-router - от 4.0.19 до 4.0.20
реакция - 16,0.30 - 16,0,34
typescript - версия "2.7.0-insiders.20180108"
В моем приложении везде, где я использую 'withRouter', теперь получаю загадочные ошибки Typescript. Я даже заменил все реквизиты интерфейса "any", чтобы попытаться заставить его работать.
import * as React from 'react';
import { Switch, Route, withRouter} from 'react-router-dom';
import { Login } from './Login';
import { connect } from 'react-redux';
import { RootAction, RootState } from './_redux';
class MainForm extends React.Component<any> {
constructor(props: any) {
super(props);
}
render() {
return (
<Switch>
<Route exact={true} path="/" component={Login}/>
<Route path="/accounts" component={AccountsView}/>
</Switch>
);
}
}
const mapStateToProps = (state: RootState) => ({
state
});
export const Main = withRouter(connect(mapStateToProps)(MainForm);
ошибка TS2345: аргумент типа 'ComponentClass > и { WrappedComponent: ComponentType; } 'не может быть отнесен к параметр типа "ComponentType > ". Тип 'ComponentClass > и {WrappedComponent: ComponentType; } 'не присваивается типу 'StatelessComponent > '. Введите "ComponentClass" и {WrappedComponent: ComponentType; } 'не соответствует подписи' (реквизит: RouteComponentProps и {children?: ReactNode; }, context?: any): ReactElement | нуль".
Если я преобразую последнюю строку в следующую строку:
export const Main = connect(mapStateToProps)(MainForm);
Я не получаю ошибок. серьезно расстроены здесь.
Благодаря
EDIT, я изменился на
export const Main = connect(mapStateToProps)(withRouter(MainForm));
как это предложил Майанк Шукла. но теперь получите ошибку:
ошибка TS2345: аргумент типа "ComponentClass > " не присваивается параметру типа 'ComponentType < {state: RootState; } и DispatchProp > '. Тип 'ComponentClass > ' не присваивается типу 'StatelessComponent < {state: RootState; } & DispatchProp > ". Тип 'ComponentClass > ' не соответствует сигнатуре '(реквизиты: {state: RootState;} и DispatchProp и { дети?: ReactNode; }, context?: any): ReactElement | нуль".
Ответы
Ответ 1
Я просто обновился до TypeScript 2.6 и получил такую же проблему.
Мне удалось разрешить его с помощью RouteComponentProps
.
Для URL http://localhost:8080/your-component/abc
и маршрута
<Route component={YourComponent} path="/your-component/:param1?" />
Компонент должен выглядеть следующим образом:
import * as React from 'react'
import { withRouter } from 'react-router-dom';
import {RouteComponentProps} from "react-router";
// Type whatever you expect in 'this.props.match.params.*'
type PathParamsType = {
param1: string,
}
// Your component own properties
type PropsType = RouteComponentProps<PathParamsType> & {
someString: string,
}
class YourComponent extends React.Component<PropsType> {
render() {
console.log(this.props); // Prints all props including routing-related
console.log(this.props.match.params.param1); // Prints 'abc'
console.log(typeof this.props.match.params.param1 === 'string'); // prints 'true'
return <div>...</div>;
}
}
export default withRouter(YourComponent);
Ответ 2
Я должен решить это так:
import * as React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
interface IProps extends RouteComponentProps<any> {
title: string;
}
class MyComp extends React.Component<IProps> {
public render(){
return (
<h1>{this.props.title}</h1>
)
}
}
export default withRouter<IProps>(MyComp);
Ответ 3
Вот как я обычно создаю набранные компоненты React:
// These props are provided when creating the component
interface OwnProps {
// ...
}
// These props are provided via connecting the component to the store
interface StateProps {
// ...
}
// These props are provided by the router
interface PathProps {
// ...
}
class Component extends React.Component<OwnProps & StateProps & RouteComponentProps<PathProps>> {
// ...
}
const mapStateToProps = (state: State, props: OwnProps): StateProps => ({
// ...
});
export default withRouter(
connect(mapStateToProps)(Component)
);
Ответ 4
Другое решение, использующее декораторы
import { withRouter, RouteComponentProps } from "react-router";
// inform we match url /:id
interface IMatchParams {
id: string;
}
// Note we use Partial<RouteComponentProps> to make all RouteComponentProps as optional for high order component
interface IComponentProps extends Partial<RouteComponentProps<IMatchParams>> {
myPersonalProp: string;
}
@withRouter
export default class MyClass extends React.Component<IComponentProps>{
public componentDidMount(){
console.log(this.props.match.params.id);
}
}
Ответ 5
Вариант рабочего синтаксиса для приложения Type Script:
import * as React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
interface ComponentProps {
// Your properties here
}
interface ComponentState {
// Your properties here
}
interface MapStateToPropsTypes {
// Your properties here
}
interface MapDispatchToPropsTypes {
// Your properties here
}
class MyComponentName extends React.Component<ComponentProps, ComponentState> {
constructor(props: ComponentProps) {
super(props);
}
}
export default withRouter(
connect<MapStateToPropsTypes, MapDispatchToPropsTypes>(
mapStateToProps,
mapDispatchToProps
)(MyComponentName) as any
);
Ответ 6
Здесь я использую подход с функциональной реакцией
import { RouteComponentProps } from "react-router";
interface Props extends RouteComponentProps {
thing: Thing | false;
onAction?: () => void;
}
export default withRouter(({ thing, onAction, history }: Props) => {
Ответ 7
Я боролся с очень похожей/такой же проблемой с Typescript 3.6 и не мог найти решение онлайн, поэтому я поделюсь своим собственным решением здесь. Надеюсь, это поможет кому-то работать с более сложным приложением.
import React, { memo } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { ThunkDispatch } from 'redux-thunk';
import { connect } from 'react-redux';
import { AnyAction } from 'redux';
interface IStateProps {
name: string;
sessionLanguage: string;
}
interface IDispatchProps {
handleLogout: () => void;
}
type Props = IStateProps & IDispatchProps & RouteComponentProps<any>;
const MyCoolComponent = ({
sessionLanguage,
handleLogout,
history,
}: Props) => {
return null;
};
const mapStateToProps = (state: IAppState): IStateProps => ({
name: state.getIn(['session', 'name']),
sessionLanguage: state.getIn(['session', 'language']),
});
const mapDispatchToProps = (
dispatch: ThunkDispatch<{}, {}, AnyAction>
): IDispatchProps => ({
handleLogout: async () => {
await dispatch(logout());
},
});
export default withRouter(
connect<IStateProps, IDispatchProps, {}, IAppState>(
mapStateToProps,
mapDispatchToProps
)(memo(NavigationLayout))
);
Некоторые заметки:
- Важными частями являются интерфейсы, RouteComponentProps, тип Props, типизация компонентов React и экспорт по умолчанию с помощью роутера (...). mapStateToProps и mapDispatchToProps являются лишь примерами.
- IAppState определяет тип приложений в моем магазине. Если у вас его нет.
- Я использую неизменное хранилище редуксов (вот почему "state.getIn...").