我需要创建一个 React 高阶组件来保护应用程序中的路由免受没有访问令牌的用户的侵害。然后使用该 HOC 将组件包装在父组件上,如下所示:
<Route
exact
path={INDEX_URL}
render={isAuthenticated((props: any) => (<LandingPage {...props} />))}
/>
我正在使用打字稿,并且我在连接功能和react-router-dom的路由器方面遇到了一些问题。
请问有人可以帮我吗?谢谢你,祝你周末愉快!😀
我已经尝试扩展我的接口与RouterProps和/或路由器,但没有一个有效。这似乎是一些与打字相关的问题,但我无法弄清楚它到底是什么。
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]
withRouter()
具有为其包装的组件提供道具的效果。因此,为了使用它,您要包装的组件必须期望这些道具。在这种情况下,Authenticated
只期待IAuthenticatedProps
,但withRouter()
提供了更多。所以TypeScript之所以抱怨,是因为withRouter()
试图为Authenticated
没有说出它所期望的Authenticated
提供道具。
withRouter()
提供的道具在接口RouteComponentProps
中定义。尝试将其添加到您的道具类型中,以便Authenticated
:
class Authenticated extends React.Component<
IAuthenticatedProps & RouteComponentProps<{}>,
IAuthenticatedState
> {
// ...
}
您还可以从IAuthenticatedProps
界面中删除location
,因为这也包含在RouteComponentProps
界面中。
另一个问题是Route
中的render
道具需要一个函数,而不是任何旧的 React 组件类型。由于isAuthenticated()
返回一个React.ComponentClass
,因此您需要执行以下操作:
const Authenticated = isAuthenticated(LandingPage);
// ...
<Route
exact
path={INDEX_URL}
render={(props: any) => <Authenticated {...props} />}
/>