从HOC返回的组件的Typescript接口中删除HOC注入的prop?

时间:2020-10-22 10:36:13

标签: reactjs typescript react-props higher-order-components

我正在尝试制作一个高阶组件,该组件从当前上下文中获取一个函数并将其注入到包装组件中的prop中,并且仍然保持Props接口。

我像这样包裹它:

interface Props extends AsyncRequestHandlerProps {
  bla: string;
}

class MyComponent extends React.Component<Props> {
 // ....
}

export default withAsyncRequestHandler(MyComponent)

我已经这样定义了withAsyncRequestHandler

export interface AsyncRequestHandlerProps {
  asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>;
}

type PropsWithoutInjectedHandler<P> = Omit<P, keyof AsyncRequestHandlerProps>;


export function withAsyncRequestHandler<P>(Component: React.ComponentType<P>) {
  return class ComponentWithAsyncRequestHandler extends React.Component<
    PropsWithoutInjectedHandler<P>
  > {
    static contextType = AsyncHandlerContext;
    context!: AsyncHandlerContext | null;
    render = () => {
      const asyncRequestHandler: <T>(
        promise: Promise<T>
      ) => Promise<T | null> = (promise) => {
        if (this.context === null) {
          throw new Error(
            "withAsyncRequestHandler should only wrap components that are mounted inside <AsyncHandler />."
          );
        }
        return AsyncRequest(promise, this.context);
      };
      const { ...props } = this.props;
      return (
        <Component
          {...props}
          asyncRequestHandler={asyncRequestHandler}
        ></Component>
      );
    };
  };
}

MyComponent道具和bla道具都是asyncRequestHandler的直接签名。我想要的是包装器HOC将仅使用bla道具返回组件签名,因为已经注入了asyncRequestHandler

此HOC的外部接口似乎正常工作,在安装包装好的组件时,我可以从打字稿中获取剩余的道具。

但是在HOC内部,我得到一个错误:

我当前的代码在我将<Component>安装到render()的那一行上给出了此错误。

Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & P & { children?: ReactNode; }'.
  Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'P'.
    'P' could be instantiated with an arbitrary type which could be unrelated to 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }'.ts(2322)

我猜问题出在Omit<P, keyof AsyncRequestHandlerProps>构造及其用法上?

1 个答案:

答案 0 :(得分:1)

根据https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046,这是TS中的错误。

从3.2开始,泛型的散布运算符的行为已更改。显然,道具的类型会被消除,这是负面的副作用,但是您可以通过在将{... props as P}散布到包装的组件中时将其投射回P来解决此问题。

因此,请尝试以下操作:

<Component
      {...props as P}
      asyncRequestHandler={asyncRequestHandler}
/>