Reputation: 197
I'm implementing a generic component which accept as
prop as any HTML element in TypeScript.
<Component as='div' {...myProps} {...divProps} />
<Component as='button' {...myProps} {...buttonProps} />
I just get lost while trying to define my component's prop as any HTML element.
Please share your advice.
Thanks.
Upvotes: 12
Views: 10587
Reputation: 160
The following article describes building a strongly typed polymorphic component.
Here is a summary of how to do it. The critical point is to use 2 generic types provided by react, these types are ElementType and ComponentPropsWithoutRef. ElementType represents a valid React Component or HTMLElement, ComponentPropsWithoutRef can infer the props of Component or an element.
import type {
ComponentPropsWithoutRef,
ElementType,
PropsWithChildren,
} from 'react';
type PolymorphicAsProp<E extends ElementType> = {
as?: E;
};
type PolymorphicProps<E extends ElementType> = PropsWithChildren<
ComponentPropsWithoutRef<E> & PolymorphicAsProp<E>
>;
const defaultElement = 'p';
type TextProps<E extends ElementType = typeof defaultElement> =
PolymorphicProps<E> & {
color?: 'primary' | 'secondary';
};
function Text<E extends ElementType = typeof defaultElement>({
as,
children,
color = 'primary',
className,
...restProps
}: TextProps<E>) {
const Component = as ?? defaultElement;
const customClassName = 'some-custom-class-name';
return (
<Component {...restProps} className={className + ' ' + customClassName}>
{children}
</Component>
);
}
Here is some demo of Text
component :
const Demo = () => {
return (
<div>
<Text as="h1">Hello</Text>
// With `a` you can pass href and it's strongly typed
<Text as="a" href="/test-url">
Hy
</Text>
</div>
);
};
Upvotes: 8
Reputation: 4588
Use somthing like this:
interface IProps {
as: React.ElementType;
}
export const Component = (props: IProps) => {
const { as: Cmp = "div", ...rest } = props;
return <Cmp {...rest} />;
};
Upvotes: 9