是否可以从作为道具传递的未知组件中推断道具的正确类型?
在已知组件(当前文件中存在)的情况下,我可以获得道具:
type ButtonProps = React.ComponentProps<typeof Button>;
但是,如果我想创建一个通用组件Box
,该通用组件接受as
道具中的组件,并接受props
道具中的组件的道具。该组件可以添加一些默认道具,具有某些行为,没关系。基本上与高阶组件相似,但动态。
import React from "react";
export interface BoxProps<TComponent> {
as?: TComponent;
props?: SomehowInfer<TComponent>; // is it possible?
}
export function Box({ as: Component, props }: BoxProps) {
// Note: it doesn't have to be typed within the Box (I can pass anything, I can control it)
return <Component className="box" title="This is Box!" {...props} />;
}
function MyButton(props: {onClick: () => void}) {
return <button className="my-button" {...props} />;
}
// usage:
function Example() {
// I want here the props to be typed based on what I pass to as. Without using typeof or explicitly passing the generic type.
return (
<div>
<Box
as={MyButton}
props={{
onClick: () => {
console.log("clicked");
}
}}
>
Click me.
</Box>
</div>
);
}
要求:
React.ComponentType<Props>
)答案 0 :(得分:2)
您可以使用预定义的反应类型ComponentProps
从组件类型中提取道具类型。
import React from "react";
export type BoxProps<TComponent extends React.ComponentType<any>> = {
as: TComponent;
props: React.ComponentProps<TComponent>;
}
export function Box<TComponent extends React.ComponentType<any>>({ as: Component, props }: BoxProps<TComponent>) {
return <div className="box" title="This is Box!">
<Component {...props} />;
</div>
}
function MyButton(props: {onClick: () => void}) {
return <button className="my-button" {...props} />;
}
// usage:
function Example() {
// I want here the props to be typed based on what I pass to as. Without using typeof or explicitly passing the generic type.
return (
<div>
<Box
as={MyButton}
props={{ onClick: () => { } }}
></Box>
</div>
);
}
根据您的确切用例,解决方案可能会有所不同,但是基本思想是相似的。例如,您可以稍微旋转一下类型,然后将props作为BoxProps
的type参数。这样,您可以约束组件props具有可以在Box
组件内部提供的某些特定属性:
export type BoxProps<TProps extends {title: string}> = {
as: React.ComponentType<TProps>;
} & {
props: Omit<TProps, 'title'>;
}
export function Box<TProps extends {title: string}>({ as: Component, props }: BoxProps<TProps>) {
return <div className="box" title="This is Box!">
<Component title="Title from box" {...props as TProps} />;
</div>
}
如果要使用固有标记,还可以将keyof JSX.IntrinsicElements
添加到TComponent
约束中:
export type BoxProps<TComponent extends React.ComponentType<any> | keyof JSX.IntrinsicElements> = {
as: TComponent;
props: React.ComponentProps<TComponent>;
}
export function Box<TComponent extends React.ComponentType<any>| keyof JSX.IntrinsicElements>({ as: Component, props }: BoxProps<TComponent>) {
return <div className="box" title="This is Box!">
<Component {...props} />;
</div>
}