HOC中省略道具

时间:2019-07-03 10:08:40

标签: javascript reactjs typescript

关于在HoC中省略道具有一个不寻常的问题

我有反应成分:

interface IMyComponentProps {
  prop1: string,
  prop2: Function,
  items1: string[],
  items2: string[],
}

我有HOC,它接受了这个组件并将item1和items2传递给它

interface IWithItems {
  items1: string[],
  items2: string[],
}

type WithoutItems<T extends IWithItems> = Omit<T, 'items1'|'items2'>;


function HoC<T extends IWithItems>(
  WrappedComponent:
    React.ComponentClass<T>
    | React.FunctionComponent<T>,
): React.ComponentClass<WithoutItems<T>> {
  class WithItemsWrapper extends React.Component<WithoutItems<T>, IWithItems> {

    state = {
      items1: [],
      items2: [],
    };

    async componentDidMount() {
      const items1 = await this.getItems1();
      const items2 = await this.getItems2();

      this.setState({
        items1,
        items2,
      });
    }

    getItems1 = () => (
      // from backend
    );

    getItems2 = () => (
      // from backend
    );

    render() {
      return (
        <WrappedComponent
          {...this.props}
          items1={this.state.items1}
          items2={this.state.items2}
        />
      );
    }
  }

  return hoistNonReactStatics(WithItemsWrapper, WrappedComponent);
}

包装的组件具有自己的道具,这些道具包含item1,item2。 HoC从后端提取项目并将其传递给包装的组件

在我的index.ts文件中,我将其导出为

export default HoC(MyComponent);

想法是,在此导出并导入到其他文件MyComponent中之后,应该需要prop1和prop2,但不需要item1和item2,因为它们已经在HoC中通过了。

但是现在它说

Error:(59, 12) TS2322: Type 'Readonly<Pick<T, Exclude<keyof T, "items1" | "items2">>> & { items1: never[]; items2: never[]; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & T & { children?: ReactNode; }'.
  Type 'Readonly<Pick<T, Exclude<keyof T, "items1" | "items2">>> & { items1: never[]; items2: never[]; children?: ReactNode; }' is not assignable to type 'T'.

是否可能,如果可以-我在做什么错了?

2 个答案:

答案 0 :(得分:0)

您采取相反的方式。 HoC接受包含items1items2的组件,并返回不包含items1items2的HOC。所以对于组件

let ResultingComponent = HoC(MyComponent);

您应仅提供prop1prop2items1items2将由HoC填充。

如果您希望传递不包含items1items2的组件,但生成的组件包含items1items2,则应该这样做

function HoC<T>(
    WrappedComponent:
        React.ComponentClass<T>
        | React.FunctionComponent<T>,
): React.ComponentClass<T & IWithItems> {
    class WithItemsWrapper extends React.Component<T & IWithItems, IWithItems> {

        render() {
            return (
                <>
                // Do some rendering based on this.props.items1 and this.props.items2
                    <div>{this.props.items1.map(e => (<div>{e}</div>))}</div>
                    <WrappedComponent
                        {...this.props}
                    />
                </>
            );
        }
    }

    return hoistNonReactStatics(WithItemsWrapper, WrappedComponent);
}

但是请注意,在这种情况下,应将item1item2提供给HoC的结果组件。在HoC内部,您不应该从后端接收这些道具,但是您应该基于这些道具进行渲染,并且不要将其传递给WrappedComponent

答案 1 :(得分:0)

我想我找到了解决方法

首先简化WithoutItems并更改HOC定义

import { pipeOne } from './pipeone.pipe';

const transformedItems = new pipeOne().transform(this.items);

接下来的事情是使道具地图显式输入P

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
type Diff<T, K> = Omit<T, keyof K>;

type WithoutItems<T> = Diff<T, IWithItems>;

function HoC<P>(
  WrappedComponent:
    React.ComponentClass<P>
    | React.FunctionComponent<P>,
): React.ComponentClass<WithoutItems<P>> {
  class WithItemsWrapper extends React.Component<WithoutItems<P>, IWithItems> {

所有其他事物保持不变。


解决方案已建立here