Как мне создать React-компонент высокого порядка, подключенный к Redux с использованием Typescript? - PullRequest
0 голосов
/ 18 января 2019

Мне нужно создать компонент React High-Order для защиты маршрутов в моем приложении от пользователей, у которых нет токена доступа. Затем с помощью этого HOC оберните Компонент, как этот, в родительский компонент:

<Route
    exact
    path={INDEX_URL}
    render={isAuthenticated((props: any) => (<LandingPage {...props} />))}
/>

Я использую Typescript, и у меня возникли некоторые проблемы с функцией соединения и withRouter из response-router-dom.

Может кто-нибудь помочь мне, пожалуйста? Спасибо и хороших выходных! ?

Я уже пытался расширить свой интерфейс с помощью RouterProps и / или withRouter, но ни один не помог. Кажется, это какая-то проблема, связанная с печатанием, но я не могу точно понять, что это такое.

import * as React from 'react';
import { Redirect, withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import * as H from 'history';

// Constants
import { LOGIN_URL } from '../../../data/constants/index.constants';

interface IAuthenticatedProps {
    accessToken: string | null;
    location: H.Location;
}

interface IAuthenticatedState {
    isAuthenticated: boolean | undefined;
}

/**
 * @description Higher-order component (HOC) to wrap Authenticated pages
 * @date 2019-01-18
 * @class Authenticated
 * @extends {React.Component<IAuthenticatedProps, any>}
 */
const isAuthenticated = (ComposedComponent: any) => {
    class Authenticated extends React.Component<
        IAuthenticatedProps,
        IAuthenticatedState
    > {
(...)
    function mapStateToProps(state: any) {
        return {
            accessToken: state.authentication.accessToken,
        };
    }

    return withRouter(connect(mapStateToProps)(Authenticated));
};

export default isAuthenticated;

Я не ожидал никаких проблем, но Typescript дает мне следующее:

[ts]
Argument of type 'ConnectedComponentClass<typeof Authenticated, Pick<IAuthenticatedProps, "location">>' is not assignable to parameter of type 'ComponentType<RouteComponentProps<any, StaticContext, any>>'.
  Type 'ConnectedComponentClass<typeof Authenticated, Pick<IAuthenticatedProps, "location">>' is not assignable to type 'ComponentClass<RouteComponentProps<any, StaticContext, any>, any>'.
    Type 'Component<Pick<IAuthenticatedProps, "location">, any, any>' is not assignable to type 'Component<RouteComponentProps<any, StaticContext, any>, any, any>'.
      Types of property 'props' are incompatible.
        Type 'Readonly<{ children?: ReactNode; }> & Readonly<Pick<IAuthenticatedProps, "location">>' is not assignable to type 'Readonly<{ children?: ReactNode; }> & Readonly<RouteComponentProps<any, StaticContext, any>>'.
          Type 'Readonly<{ children?: ReactNode; }> & Readonly<Pick<IAuthenticatedProps, "location">>' is missing the following properties from type 'Readonly<RouteComponentProps<any, StaticContext, any>>': history, match [2345]

1 Ответ

0 голосов
/ 18 января 2019

withRouter() имеет эффект предоставления реквизита для компонента, который он упаковывает. Поэтому, чтобы использовать его, компонент, который вы хотите обернуть, должен ожидать этих реквизитов. В этом случае Authenticated ожидает только IAuthenticatedProps, но withRouter() предоставляет гораздо больше. Поэтому TypeScript жалуется, потому что withRouter() пытается предоставить реквизит Authenticated, который Authenticated не говорит, что он ожидает.

Подставки, которые предоставляет withRouter(), определены в интерфейсе RouteComponentProps. Попробуйте добавить это к вашему типу опоры для Authenticated:

  class Authenticated extends React.Component<
    IAuthenticatedProps & RouteComponentProps<{}>,
    IAuthenticatedState
  > {
    // ...
  }

Вы также можете удалить location из интерфейса IAuthenticatedProps, поскольку он также включен в интерфейс RouteComponentProps.

Еще одна проблема заключается в том, что render prop в Route ожидает функцию, а не какой-либо старый тип компонента React. Поскольку isAuthenticated() возвращает React.ComponentClass, вам нужно сделать что-то вроде следующего:

const Authenticated = isAuthenticated(LandingPage);
// ...
<Route
  exact
  path={INDEX_URL}
  render={(props: any) => <Authenticated {...props} />}
/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...