You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在带必填Props的React组件中传递任意Props(TypeScript)

问题:React可复用Dialog组件的TypeScript类型优化

我编写了如下React组件:

const GlobalDialogView = ({
  PassedComponent,
  open,
  size,
  bodyDivider,
  bodyClasses,
  headerTitle,
  dismiss,
  ...rest
}: Props) => {
  return (
    <Fragment>
      <Dialog open={open} handler={() => {}} size={size ? size : "md"}>
        {headerTitle && <DialogHeader>{headerTitle}</DialogHeader>}
        <DialogBody
          className={`${bodyClasses ? bodyClasses : ""}`}
          divider={bodyDivider ? bodyDivider : false}
        >
          <PassedComponent {...rest} />
        </DialogBody>
      </Dialog>
    </Fragment>
  );
};

对应的Props类型声明:

type Props = {
  PassedComponent: React.ComponentType;
  open: boolean;
  headerTitle?: string;
  bodyDivider?: boolean;
  bodyClasses?: string;
  size?: "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
  dismiss?: DismissType
};

我希望将GlobalDialogView打造为可复用组件,能够通过...rest向PassedComponent传递任意Props,例如:

<GlobalDialogView open={open} PassedComponent={AnotherComponet} value={"another componet value"} anotherRandomProp="" />;

const AnotherComponet = ({ value, anotherRandomProp }) => {
  return <Fragment></Fragment>;
};

我知道可以用any来实现,但需要保留部分必填Props的类型校验,请问在TypeScript中有没有合适的解决方案?


解决方案:使用泛型约束实现类型安全的Props传递

在TypeScript中,通过泛型可以让GlobalDialogView的Props类型与传入的子组件所需Props自动关联,既保留组件自身必填/可选Props的校验,又能对传递给子组件的参数做类型检查,完全不需要依赖any。

1. 修改Props类型为泛型类型

将原有的Props改为泛型类型,合并组件自身Props与子组件所需Props:

type GlobalDialogProps<T = {}> = {
  PassedComponent: React.ComponentType<T>;
  open: boolean;
  headerTitle?: string;
  bodyDivider?: boolean;
  bodyClasses?: string;
  size?: "xs" | "sm" | "md" | "lg" | "xl" | "xxl";
  dismiss?: DismissType;
} & T;

这里的& T表示把组件自身的Props和子组件的Props做合并,TypeScript会自动校验传入的参数是否同时满足两者的要求。

2. 改造组件为泛型组件

将GlobalDialogView定义为泛型组件,同时简化默认值逻辑:

const GlobalDialogView = <T extends {}>({
  PassedComponent,
  open,
  size = "md",
  bodyDivider = false,
  bodyClasses = "",
  headerTitle,
  dismiss,
  ...rest
}: GlobalDialogProps<T>) => {
  return (
    <Fragment>
      <Dialog open={open} handler={() => {}} size={size}>
        {headerTitle && <DialogHeader>{headerTitle}</DialogHeader>}
        <DialogBody
          className={bodyClasses}
          divider={bodyDivider}
        >
          <PassedComponent {...rest as T} />
        </DialogBody>
      </Dialog>
    </Fragment>
  );
};
  • 给size、bodyDivider、bodyClasses设置默认值,替代原有的三元表达式,代码更简洁。
  • ...rest as T是类型断言,确保剩余参数严格符合子组件的Props类型。

3. 使用示例(自动类型校验)

当传入子组件时,TypeScript会自动检查传递的参数是否符合子组件的Props要求:

// 定义子组件及其Props类型
type AnotherComponentProps = {
  value: string;
  anotherRandomProp: string;
};

const AnotherComponent = ({ value, anotherRandomProp }: AnotherComponentProps) => {
  return (
    <div>
      <p>{value}</p>
      <p>{anotherRandomProp}</p>
    </div>
  );
};

// 使用GlobalDialogView,TypeScript会自动校验所有参数
<GlobalDialogView
  open={true}
  PassedComponent={AnotherComponent}
  value="another component value"
  anotherRandomProp="test"
  size="lg"
/>;

如果少传了子组件的必填Props(比如value),或者传入了不符合类型的参数,TypeScript会直接抛出错误,实现类型安全。

额外优化:支持无额外Props的子组件

如果子组件不需要额外Props,可以直接使用GlobalDialogView而无需指定泛型,因为泛型参数T默认值为{}:

const EmptyComponent = () => <div>Empty</div>;

<GlobalDialogView open={true} PassedComponent={EmptyComponent} />;

内容的提问来源于stack exchange,提问作者Arijit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 18:22:01