I have a CustomIcon
component that I use sometimes for my icons, and other times I use MUI's icons. I have a type with a variable defined as:
type ParentComponentProps = {
icon: React.ReactElement<SvgIconProps> | typeof CustomIcon;
};
This way, I can call ParentComponent
either this way:
<ParentComponent icon={<HomeIcon />}/>
or
<ParentComponent icon={<CustomIcon {...args}/>}/>
I want a way to determine from the value of icon
if it's using the MUI icon or my CustomIcon
. Within ParentComponent
, I want to add arguments to the icon
that gets passed in so that the consumers won't have to (eg I want to add className
classes in addition to what the consumer might specify).
I've tried various ways to approach this, using typeof
, instanceof
, and ReturnType
but they're all generally limited due to needing a value for the comparison rather than a type.
Is there a way to solve this using a condition, or does it need to be solved another way?
the type of created react component (in the format of <Icon />
) is always be JSX.Element
, if you need to some type checks, you should pass the component itself into the props
so the component props will be like belows, note that the name is changes to Icon
because if you do <icon />
inside, it will be consider you are try to use a native element call icon
:
type ParentComponentProps = {
Icon: React.ComponentType<SvgIconProps> | typeof CustomIcon;
};
but usually I will let the props of CustomIcon
(assume it is called CustomIconProps
) compatible with SvgIconProps
, and the types will be:
type CustomIconProps = SvgIconProps & {
// ...
};
type ParentComponentProps = {
Icon: React.ComponentType<SvgIconProps>;
};
which will be more clear.
and the usage:
<ParentComponent Icon={HomeIcon}/>
<ParentComponent Icon={CustomIcon}/>
if you need to pass args
to CustomIcon
:
<ParentComponent Icon={(props: CustomIconProps) => <CustomIcon {...props} {...args}/>}/>
I want a way to determine from the value of icon
Where do you want to use that?
If you need it to determine another type, for example to type an style
prop, you can do something like this:
type SvgIcon = React.ReactElement<SvgIconProps>
type ParentComponentProps<Icon extends SvgIcon | typeof CustomIcon> = {
icon: Icon;
style: Icon extends SvgIcon ? Type1 : Type2
};
Even when you do:
<ParentComponent
icon={<CustomIcon {...args}/>}
/>
...you are actually passing a ReactElement
to the icon
prop.
More generally, this is similar to the children
prop, or any slot content prop. We generally type them as ReactNode
, which also takes a string
, null
, or an array of ReactNode
.
It is indeed possible to tell from a ReactElement
from which Component it was built, typically by looking into its type.name
property, but you need to guard it first, as described eg in Accessing child.type.name in React Typescript
function ParentComponent({
icon
}: {
icon: React.ReactElement
}) {
if (React.isValidElement(icon) && typeof icon.type === "function") {
icon.type.name // Okay
}
return <></>
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.