我有一个组件,其根节点可以用传递的prop的值覆盖。
interface Props {
propA?: string
as?: React.ElementType
}
const OverridableComponent = (props: Props) => {
const { as: Tag = 'div', ...otherProps } = props
return <Tag {...props} />
}
和另一个将用作as
的组件。
interface SomeComponentProps {
propB: string //<-- mandatory prop
children?: React.ReactNode
}
const SomeComponent = (props: SomeComponentProps) => {
return <div someProp={props.propB}>{props.children}</div>
}
所以,我想实现的结果是这样的
<OverridableComponent propA='optionalProp' as={SomeComponent} />
我希望OverridableComponent
合并来自SomeComponent
的道具。
<OverridableComponent propA='optionalProp' as={SomeComponent}
propB={/*required form SomeComponentProps */'someValue />
为实现这一点,我尝试使用泛型。
type Props<T extends ElementType> = {
propA?: string
as?: T
} & React.ComponentProps<T>
它适用于传递as
属性的情况,但如果不传递,则允许每个传递的属性,甚至from='string'
都允许,因为React.ElementType的SVG属性允许它。
有什么想法可以改善这种情况吗?
答案 0 :(得分:1)
您是否可以明确地将所需的React.ElementType
作为Generic type arguments in JSX传递?这样,您就不必依赖编译器推断,并且可以适当地缩小类型。
组件:
const AppWithComponent = () => (
<OverridableComponent<typeof SomeComponent>
propA="pa"
propB="pb"
// className="ajsf" ; error
// from='string' ; error
as={SomeComponent}
/>
);
内在元素:
const AppWithIntrinsicElementExplicit = () => (
<OverridableComponent<"div">
propA="pa"
// propB="pb" ; error
className="yehaa"
// from='string' ; error
as="div" // you also can drop this attribute
/>
);