TypeScript Rest Props - 允许任何道具或告诉组件它们将成为哪些道具

TypeScript Rest Props - allow any props or tell the component which props they're going to be

我正在使用 TypeScript 构建一个 React 应用程序。我有一个 RequiresPermission 组件,它基于谓词,应该呈现一个或另一个组件并转发所有道具。

type Props = {
  NotPermittedComponent: React.ComponentType;
  PermittedComponent: React.ComponentType;
  isPermitted: boolean;
};

const RequiresPermisson = ({
  NotPermittedComponent,
  PermittedComponent,
  isPermitted,
  ...rest
}: Props) =>
  isPermitted ? (
    <PermittedComponent {...rest} />
  ) : (
    <NotPermittedComponent {...rest} />
  );

export default RequiresPermisson;

当我渲染组件时,TypeScript 大喊 RequiresPermission in:

const PERMITTED_TEXT = 'permitted';
const NOT_PERMITTED_TEXT = 'not-permitted';

type TestPropsProps = {
  text: string;
};

const NotPermittedTestComponent: React.FunctionComponent<TestPropsProps> = ({
  text,
}) => (
  <div>
    <span>{NOT_PERMITTED_TEXT}</span>
    {text}
  </div>
);

const PermittedTestComponent: React.FunctionComponent<TestPropsProps> = ({
  text,
}) => (
  <div>
    <span>{PERMITTED_TEXT}</span>
    {text}
  </div>
);

const createProps = ({
  NotPermittedComponent = NotPermittedTestComponent,
  PermittedComponent = PermittedTestComponent,
  isPermitted = false,
  text = 'foo',
} = {}) => ({
  NotPermittedComponent,
  PermittedComponent,
  isPermitted,
  text,
});

const props = createProps();
render(<RequiresPermission {...props} />);

说:

Type '{ NotPermittedComponent: FunctionComponent<TestPropsProps>; PermittedComponent: FunctionComponent<TestPropsProps>; isPermitted: boolean; text: string; }' is not assignable to type '{ NotPermittedComponent: ComponentType<{}>; PermittedComponent: ComponentType<{}>; isPermitted: boolean; }'.
  Types of property 'NotPermittedComponent' are incompatible.
    Type 'FunctionComponent<TestPropsProps>' is not assignable to type 'ComponentType<{}>'.
      Type 'FunctionComponent<TestPropsProps>' is not assignable to type 'FunctionComponent<{}>'.
        Types of parameters 'props' and 'props' are incompatible.
          Type '{ children?: ReactNode; }' is not assignable to type 'PropsWithChildren<TestPropsProps>'.
            Property 'text' is missing in type '{ children?: ReactNode; }' but required in type 'TestPropsProps'.

我也试过 Record<string, unknown> 作为 props 但这也不起作用。

如何解决此问题以传递 props 或允许任何(不是类型 any)的 props 以便 ...rest 参数起作用?

您需要来自打字稿的通用类型:https://www.typescriptlang.org/docs/handbook/generics.html

简而言之,这些是动态类型,取决于输入的内容。

在下面的代码中,我们将传递给类型 T 的所有 props 赋值,并告诉 typescript 这些 props 是:required props NotPermittedComponent PermittedComponent isPermitted 以及所有 rest,在本例中成为类型 T.

type Props = {
  NotPermittedComponent: React.ComponentType;
  PermittedComponent: React.ComponentType;
  isPermitted: boolean;
};

const RequiresPermisson = <T extends Record<string, unknown>>({
  NotPermittedComponent,
  PermittedComponent,
  isPermitted,
  ...rest
}: Props & T) =>
  isPermitted ? (
    <PermittedComponent {...rest} />
  ) : (
    <NotPermittedComponent {...rest} />
  );

export default RequiresPermisson;

不确定这是否是最优雅的解决方案,但我刚刚组合了所有道具类型。这使您可以对所有道具进行类型检查。我必须转发所有道具,因为我无法确定子组件不需要像 isPermitted 这样的东西。

interface Props <A, B>{
  NotPermittedComponent: React.ComponentType<A>;
  PermittedComponent: React.ComponentType<B>;
  isPermitted: boolean;
}

const RequiresPermisson = <A, B>(props: Props<A, B> & A & B): JSX.Element => {
  const {
    NotPermittedComponent,
    PermittedComponent,
    isPermitted,
  } = props
  return isPermitted ? (
    <PermittedComponent {...props} />
  ) : (
    <NotPermittedComponent {...props} />
  )
}