如何在带必填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
相关产品推荐
相关产品推荐

