我想知道在以下场景中我是否对 API HOC 的返回类型有正确的输入:
我有一个 Authentication HOC,
withAuthentication
,它将身份验证服务注入到组件的 props 中。我有一个 API HOC,
withRestApi
它注入 API 调用,它本身使用withAuthentication
.MyComponent
需要利用withRestApi
的注入函数,并且有自己的props。
(在实际的应用程序中,withAuthentication
还需要一个 react-router HOC,但在这个例子中我试图让事情尽可能简单。)
到目前为止,我的代码基于James Ravencroft 在 HOCs 和 Typescript 上的优秀帖子,另外还有这篇关于注入 HOC props 的 SO 帖子,这有助于解决 HOC props 暴露给包装组件的父级的问题。
我想要实现的是:
this.props.getResultOfApiCall
从MyComponent
类内部访问,但对任何父组件隐藏。this.props.isAuthenticated
从WithRestApi
类内部访问,但对任何父组件隐藏。- 能够设置
componentProp
在MyComponent
从父组件。
代码如下:
MyBase.tsx,封闭组件纯粹是为了演示MyComponent
's prop 的使用:
import * as React from 'react';
import MyComponent from './MyComponent';
class MyBase extends React.Component {
public render() {
return (
<>
<h1>RESULT</h1>
<MyComponent componentProp={'Prop belonging to MyComponent'} />
</>
);
}
}
export default MyBase;
MyComponent.tsx,它使用 API:
import * as React from 'react';
import { IWithRestApiProps, withRestApi } from './WithRestApi';
interface IMyComponentProps extends IWithRestApiProps {
componentProp: string;
}
class MyComponent extends React.Component<IMyComponentProps> {
public render() {
return (
<>
<h2>Component prop: {this.props.componentProp}</h2>
<h2>API result: {this.props.getResultOfApiCall()}</h2>
</>
);
}
}
export default withRestApi(MyComponent);
WithAuthentication.tsx(把这个放在第一位,因为这不是问题......据我所知):
import * as React from 'react';
export interface IWithAuthenticationProps {
isAuthenticated: () => boolean;
}
export const withAuthentication = <P extends IWithAuthenticationProps>(Component: React.ComponentType<P>):
React.ComponentType<Pick<P, Exclude<keyof P, keyof IWithAuthenticationProps>>> =>
class WithAuthentication extends React.Component<P> {
public render() {
const { isAuthenticated, ...originalProps } = this.props as IWithAuthenticationProps;
return (
<Component
{...originalProps}
isAuthenticated={this.isAuthenticated}
/>
);
}
private readonly isAuthenticated = (): boolean => {
return true;
}
}
WithRestApi.tsx,其中包含打字问题。
import * as React from 'react';
import { IWithAuthenticationProps, withAuthentication } from './WithAuthentication';
export interface IWithRestApiProps extends IWithAuthenticationProps {
getResultOfApiCall: () => string;
}
export const withRestApi = <P extends IWithRestApiProps>(Component: React.ComponentType<P>):
React.ComponentType<Pick<P, Exclude<keyof P, keyof IWithRestApiProps>>> =>
withAuthentication(class WithRestApi extends React.Component<P> {
public render() {
const { getResultOfApiCall, ...originalProps } = this.props as IWithRestApiProps;
return (
<Component
{...originalProps}
getResultOfApiCall={this.getApiData}
/>
);
}
private readonly getApiData = () => {
if (this.props.isAuthenticated()) {
return 'Some API result';
} else {
return 'Not authenticated';
}
}
}) as React.ComponentType<P>; // TODO - remove this type assertion...?
这段代码生成了,但正如你所看到的,我不得不将withApi
HOC的返回值类型断言到React.ComponentType<P>
. 如果没有那个断言,我会看到这个 Typescript 错误:
[ts]
Type 'ComponentType<Pick<P, Exclude<keyof P, "isAuthenticated">>>' is not assignable to type 'ComponentType<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>>'.
Type 'ComponentClass<Pick<P, Exclude<keyof P, "isAuthenticated">>, ComponentState>' is not assignable to type 'ComponentType<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>>'.
Type 'ComponentClass<Pick<P, Exclude<keyof P, "isAuthenticated">>, ComponentState>' is not assignable to type 'ComponentClass<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>, ComponentState>'.
Type 'Pick<P, Exclude<keyof P, "isAuthenticated">>' is not assignable to type 'Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>'.
Type 'Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">' is not assignable to type 'Exclude<keyof P, "isAuthenticated">'.
这是我第一次遇到对 的需求Pick..Exclude
,所以对于在这种情况下如何匹配类型有点模糊。我想知道我在这里使用它的方式是否可以改进以消除对类型断言的需要?