React+TypeScript中Icon作为Props传递的样式与类型冲突解决
解决Icon类型与样式设置的冲突问题
方案一:传递组件而非组件实例(推荐)
这种方式符合React组件复用的最佳实践,能完美适配TypeScript类型校验。
修改父组件(Sidebar.tsx)
将原有的<HomeIcon />组件实例改为直接传递HomeIcon组件本身:
import SidevarNavigationItem from "./SidevarNavigationItem" import { HomeIcon } from "@heroicons/react/24/solid" import { StarIcon } from "@heroicons/react/24/solid" const Sidebar = () => { return ( <nav id="sidebar" className="p-2 mt-5 max-w-2xl xl:min-w-fit sticky top-20 flex-grow-0.2 text-center h-screen" > <div id="navigation"> <SidevarNavigationItem Icon={HomeIcon} name="Homepage" source="/" /> <SidevarNavigationItem Icon={StarIcon} name="Tournaments" source="/tournaments" /> </div> </nav> ) } export default Sidebar
子组件(SidebarNavigationItem.tsx)修正细节
保持React.ElementType类型,同时修正拼写错误(classname改为className):
import Link from "next/link" import { FunctionComponent } from "react" interface Props { Icon: React.ElementType name: string source: string } const SidevarNavigationItem: FunctionComponent<Props> = ({ Icon, name, source, }) => { return ( <Link href={source}> <div className="flex items-center cursor-pointer text-3xl space-x-5 justify-center"> {Icon && <Icon className="h-8 w-8 text-red-500" />} <p className="hidden sm:inline-flex font-medium">{name}</p> </div> </Link> ) } export default SidevarNavigationItem
方案二:传递组件实例并通过克隆添加样式
如果坚持在父组件传递<HomeIcon />这类实例,可以用React.cloneElement克隆元素并追加样式:
修改子组件(SidebarNavigationItem.tsx)
import Link from "next/link" import { FunctionComponent, cloneElement } from "react" interface Props { Icon: JSX.Element name: string source: string } const SidevarNavigationItem: FunctionComponent<Props> = ({ Icon, name, source, }) => { return ( <Link href={source}> <div className="flex items-center cursor-pointer text-3xl space-x-5 justify-center"> {Icon && cloneElement(Icon, { className: `${Icon.props.className || ""} h-8 w-8 text-red-500` })} <p className="hidden sm:inline-flex font-medium">{name}</p> </div> </Link> ) } export default SidevarNavigationItem
父组件保持不变
继续传递<HomeIcon />即可,子组件会自动合并原有样式与新增样式。
错误原因说明
React.ElementType代表的是组件类型(如函数组件、类组件),而你父组件传递的<HomeIcon />是已渲染完成的JSX元素实例,类型为JSX.Element,两者类型不兼容,因此TypeScript抛出错误。- 当把类型设为
JSX.Element时,直接修改元素props(如添加className)会报错,因为JSX元素是不可变的,必须通过克隆的方式修改。
内容的提问来源于stack exchange,提问作者lool
相关产品推荐
相关产品推荐

