PancakeSwap前端代码构建阶段出现'Icon'无法作为JSX组件的类型错误求助
这个错误本质是TypeScript无法确认你传入的icon属性是一个有效的JSX组件类型。从你的代码来看,icon的类型被定义为Element | Component<any, any, any>,而JSX要求组件必须是组件类/函数或者DOM元素标签字符串,直接使用Component类型会因为render()返回值的类型兼容问题报错。
下面是具体的修复步骤:
1. 修正icon的类型定义(最优方案)
首先找到SubMenuItemsProps的类型定义文件(./types),把icon的类型从Element | Component<any, any, any>改成React.ElementType——这个类型是React内置的,专门用来表示可以作为JSX组件的类型(包含函数组件、类组件、DOM标签):
// 在 ./types 文件中 import React from 'react'; export interface SubMenuItemsProps { // 其他属性... icon?: React.ElementType; }
修改后,TypeScript就能正确推断Icon是合法的JSX组件,不需要额外处理。
2. 如果无法修改props类型,添加类型断言/守卫
如果你没办法修改SubMenuItemsProps的定义(比如是第三方库的类型),可以在使用icon的时候手动做类型断言,告诉TypeScript这是一个有效的组件类型:
// 替换你代码中的 const Icon = icon; const Icon = icon as React.ElementType;
或者更严谨一点,添加类型守卫区分“已渲染的元素”和“组件”:
{icon && ( typeof icon === 'object' ? icon // 如果是已经渲染好的React元素,直接显示 : <Icon color={href === activeItem ? "secondary" : "textSubtle"} mr="4px" /> // 如果是组件,再渲染 )}
3. 额外检查:确保传入的icon值正确
还要确认你传入SubMenuItems的icon属性是组件本身(比如OpenNewIcon),而不是已经渲染的元素(比如<OpenNewIcon />)——如果是后者,直接渲染即可,不需要用<Icon />的方式调用。
修改后的完整代码示例:
import React from "react"; import { Box } from "../Box"; import { DropdownMenuItemType } from "../DropdownMenu/types"; import MenuItem from "../MenuItem/MenuItem"; import { OpenNewIcon } from "../Svg"; import StyledSubMenuItems from "./styles"; import { SubMenuItemsProps } from "./types"; const SubMenuItems: React.FC<SubMenuItemsProps> = ({ items = [], activeItem, isMobileOnly = false, ...props }) => { return ( <StyledSubMenuItems justifyContent={[isMobileOnly ? "flex-end" : "start", null, "center"]} {...props} pl={["12px", null, "0px"]} $isMobileOnly={isMobileOnly} > {items.map(({ label, href, icon, itemProps, type }) => { const isExternalLink = type === DropdownMenuItemType.EXTERNAL_LINK; const linkProps = isExternalLink ? { as: "a", target: "_blank", } : {}; return ( label && ( <Box key={label} mr="20px"> <MenuItem href={href} isActive={href === activeItem} variant="subMenu" {...itemProps} {...linkProps}> {/* 区分组件和已渲染元素 */} {icon && ( typeof icon === 'function' || typeof icon === 'string' ? React.createElement(icon, { color: href === activeItem ? "secondary" : "textSubtle", mr: "4px" }) : icon )} {label} {isExternalLink && ( <Box display={["none", null, "flex"]} style={{ alignItems: "center" }} ml="4px"> <OpenNewIcon color="textSubtle" /> </Box> )} </MenuItem> </Box> ) ); })} </StyledSubMenuItems> ); }; export default SubMenuItems;
这样就能解决构建时的TypeScript类型错误了。
内容的提问来源于stack exchange,提问作者Krishan Bandara Karunathilaka

