打字稿React HOC困境

时间:2018-11-15 05:27:26

标签: reactjs typescript

我很难让打字稿与我的HOC合作。经过多次迭代,这是我所拥有的最好的:

export interface IRequiresLoginProps {
  loggedIn: boolean;
}

type GetProps<C> = C extends ComponentType<infer P> ? P : never;

function requiresLogin<C extends ComponentType<GetProps<C>>>(Component: C) {
  const MakeTSHappy: ComponentType<GetProps<C>> = Component;
  const displayName = Component.displayName || Component.name || "Component";

  class RequiresLogin extends PureComponent<GetProps<C> & IRequiresLoginProps> {
    public static readonly displayName = `RequiresLogin(${displayName})`;

    public render() {
      const {loggedIn, ...props} = this.props as IRequiresLoginProps;
      return loggedIn ? <MakeTSHappy {...props} /> : <Login loggedIn={loggedIn} />;
    }
  }
  return hoistNonReactStatics(RequiresLogin, Component);
}

由于某种原因,使打字稿快乐的唯一方法是使用MakeTSHappy变量。如果我尝试跳过它并像<Component {...props} />一样直接使用Component,则会出现TS错误:“ JSX元素类型'Component'没有任何构造或调用签名。”

由于Component的类型扩展了ComponentType<>,所以我希望它像ComponentType<>一样工作;为什么给我一个错误?我可以将其分配给类型为ComponentType<>的变量而无需显式转换它的事实似乎在支持我的理解。

1 个答案:

答案 0 :(得分:0)

我认为您只是使它有点复杂,因为在出​​现条件类型之前存在HOC。这很好:

function requiresLogin<P extends {}, C extends ComponentType<P> = ComponentType<P>>(
  Component: ComponentType<P>
) {
  const displayName = Component.displayName || Component.name || "Component";

  class RequiresLogin extends PureComponent<P & IRequiresLoginProps> {
    public static readonly displayName = `RequiresLogin(${displayName})`;

    public render() {
      const { loggedIn, ...props } = this.props as IRequiresLoginProps;
      return loggedIn ? <Component {...props} /> : <Login loggedIn={loggedIn} />;
    }
  }
  return hoistNonReactStatics(RequiresLogin, Component);
}