Reputation: 12267
In the code below, how can I:
function DefaultIcon () {
return <svg></svg>;
}
interface ExampleProps {
icon?: React.ReactElement; // JSX.IntrinsicElements also errors
}
function Example({ icon = <DefaultIcon /> }: ExampleProps) {
const Icon = icon;
return (
<div>
{React.createElement(icon)}
{/* ^Shows Error #1 */}
{React.createElement(icon as React.ReactElement<any>)}
{/* ^Shows Error #1 */}
<Icon />
{/* ^Shows Error #2 */}
</div>
)
}
Error #1
No overload matches this call.
The last overload gave the following error.
Argument of type 'ReactElement<any, string | JSXElementConstructor<any>>'
is not assignable to parameter of type 'string | FunctionComponent<any> |
ComponentClass<any, any>'.ts(2769)
Error #2
JSX element type 'Icon' does not have any construct or call signatures.ts(2604)
Upvotes: 2
Views: 1482
Reputation: 12267
Key Insight: React.createElement()
only takes references to components (ie., Icon
), not an instance of it. To clone an instance of a component (ie., <Icon />
), use React.cloneElement()
With that in mind, here are the two methods to recreate a component:
a) To render: {icon}
b) To recreate: React.cloneElement(icon)
React.ReactElement<>
prop definition as seen in icon2
or cast the type as in icon3
.function DefaultIcon() {
return <svg></svg>;
}
interface ExampleProps {
icon?: React.ReactElement;
icon2?: React.ReactElement<SVGSVGElement>;
icon3?: React.ReactElement;
}
function Example({ icon = <DefaultIcon />, icon2, icon3 }: ExampleProps) {
return (
<div>
{icon}
{React.cloneElement(icon, { className: "block" })}
{React.isValidElement(icon2) && (
React.cloneElement(icon2, { className: "block" })
)}
{React.isValidElement(icon3) && (
React.cloneElement(icon3 as React.ReactElement<SVGSVGElement>, {
className: "block"
})
)}
</div>
);
}
a) To render: const Icon = icon
and return (<Icon />)
b) To recreate: React.createElement()
function DefaultIcon () {
return <svg></svg>;
}
interface ExampleProps {
icon?: React.FC; // <-- new type definition
}
function Example({ icon = DefaultIcon}: ExampleProps) {
const Icon = icon; // ^ new default fallback
return (
<div>
{React.createElement(icon)}
<Icon />
</div>
);
}
Upvotes: 1
Reputation: 3560
Could you please try this?
function DefaultIcon() {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4.57574 12.5757C4.34142 12.8101 4.34142 13.1899 4.57574 13.4243C4.81005 13.6586 5.18995 13.6586 5.42426 13.4243L4.57574 12.5757ZM15.6 3C15.6 2.66863 15.3314 2.4 15 2.4L9.6 2.4C9.26863 2.4 9 2.66863 9 3C9 3.33137 9.26863 3.6 9.6 3.6H14.4V8.4C14.4 8.73137 14.6686 9 15 9C15.3314 9 15.6 8.73137 15.6 8.4L15.6 3ZM5.42426 13.4243L15.4243 3.42426L14.5757 2.57574L4.57574 12.5757L5.42426 13.4243Z"
fill="#404040"
/>
</svg>
);
}
interface ExampleProps {
// eslint-disable-next-line react/require-default-props
icon?: React.ReactNode;
}
function Example({ icon = <DefaultIcon /> }: ExampleProps) {
return <div>{icon}</div>;
}
export default Example;
Upvotes: 1
Reputation: 120
The issue here is you cannot set jsx as a default value for props in typescript instead try to modify this code
const Icon = icon || DefaultIcon by using this expression we are evaluating that if the code icon is undefined DefaultIcon would be used. then remove the default value in props.
Upvotes: 0