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...").