打字稿高阶组件

时间:2019-01-28 12:07:32

标签: reactjs typescript

我在键入以下HOC时遇到问题。我已经简化了它,但是用例正在基于新的属性修改包装组件上的类。

import React, { ComponentType } from 'react';

interface Classable {
  className?: string;
}

interface Fooable {
  foo: string;
}

function fooTheClass(foo: string, className?: string): string {
  // this is a simplified example..
  return className ? `$(className) ${foo}` : foo;
}

// HOC to modify className based on a new prop.
const withFoo = <P extends Classable>(Component: ComponentType<P>): ComponentType<P & Fooable> => {
  const newComponent = ({ foo, className, ...rest }: P & Fooable) => {
    return <Component className={fooTheClass(foo, className)} {...rest} />;
  };
  return newComponent;
};

这会导致以下错误:

  

输入'{className:string; }&Pick>'不能分配给'IntrinsicAttributes类型   &P&{子代?:ReactNode; }'。输入'{className:string; }&   选择>不是   可分配给类型“ P”。 [2322]

如果不进行销毁,我可以消除该错误:

const withFoo1 = <P extends Classable>(Component: ComponentType<P>): ComponentType<P & Fooable> => {
  const newComponent = (props: P & Fooable) => {
    const { ...rest } = props;
    rest.className = fooTheClass(rest.foo, rest.className);
    delete rest.foo;
    return <Component {...rest } />;
  };
  return newComponent;
};

或使用显式强制转换:

const withFoo2 = <P extends Classable>(Component: ComponentType<P>): ComponentType<P & Fooable> => {
  const newComponent = ({ foo, className, ...rest }: P & Fooable) => {
    return <Component className={fooTheClass(foo, className)} {...(rest as unknown as P)} />;
  };
  return newComponent;
};

(请注意:

return <Component className={fooTheClass(foo, className)} {...(rest as P)} />;

不起作用)。

这两者似乎都是不明智的解决方法。有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

我认为您最好的方法是使用预定义的React.FC类型,而不是直接键入道具:

const withFoo = <P extends Classable>(
  Component: ComponentType<P>
): ComponentType<P & Fooable> => {
  const newComponent: React.FC<P & Fooable> = ({ foo, className, ...rest }) => {
    return <Component className={fooTheClass(foo, className)} {...rest as P} />;
  };
  return newComponent;
};