You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复:JSX元素类型无构造或调用签名问题

解决React TypeScript中动态创建MUI图标组件的类型错误

问题场景

你在React TypeScript项目中尝试通过Map动态获取MUI图标组件并渲染,相关代码及报错如下:

按钮配置数组

const generalButtons: MenuButton[] = [
    {
        text: "New Client",
        onClickFunction: addNewClient,
        icon: "InfoIcon"
    },
    {
        text: "New Product",
        onClickFunction: addNewClient,
        icon: "AddShoppingCartIcon"
    },
    {
        text: "New Gift",
        onClickFunction: addNewClient,
        icon: "CardGiftcardIcon"
    }
]

图标映射Map

import InfoIcon from '@mui/icons-material/Info';
import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart';
import CardGiftcardIcon from '@mui/icons-material/CardGiftcard';
import { OverridableComponent } from '@mui/material/OverridableComponent';
import { SvgIconTypeMap } from '@mui/material';

const menuIconToComponentMap: Map<string, OverridableComponent<SvgIconTypeMap<{}, "svg">> & { muiName: string; }> = new Map();

menuIconToComponentMap.set("InfoIcon", InfoIcon);
menuIconToComponentMap.set("AddShoppingCartIcon", AddShoppingCartIcon);
menuIconToComponentMap.set("CardGiftcardIcon", CardGiftcardIcon);

export default menuIconToComponentMap;

渲染代码及报错

<List>
    {generalButtons.map((button, index) => {
        const MenuIcon = menuIconToComponentMap.get(button.icon)
        return (
            <ListItem key={button.text} disablePadding>
                <ListItemButton onClick={(e) => button.onClickFunction(e)}>
                    <ListItemIcon>
                        <MenuIcon />
                    </ListItemIcon>
                    <ListItemText primary={button.text} />
                </ListItemButton>
            </ListItem>
        )
    })}
</List>

报错信息:JSX element type 'MenuIcon' does not have any construct or call signatures

问题原因

TypeScript无法确定menuIconToComponentMap.get(button.icon)的返回值一定是有效的React组件——因为Map的get方法可能返回undefined,当TypeScript推断出这种可能性时,就会认为MenuIcon不具备组件的构造/调用签名。

解决方案

步骤1:约束图标键的类型(可选但推荐)

先给MenuButton的icon字段定义精确的联合类型,确保所有配置的图标名称都存在于Map的键中:

// 定义所有可用的图标键
type MenuIconKey = "InfoIcon" | "AddShoppingCartIcon" | "CardGiftcardIcon";

// 修正MenuButton接口
interface MenuButton {
  text: string;
  onClickFunction: (e: React.MouseEvent) => void;
  icon: MenuIconKey;
}

步骤2:确保组件存在后再渲染

在渲染时添加非空检查,或者使用非空断言(更推荐前者,避免潜在的运行时错误):

方案一:安全检查(推荐)

<List>
    {generalButtons.map((button) => {
        const MenuIcon = menuIconToComponentMap.get(button.icon);
        // 若图标不存在,返回null避免渲染错误
        if (!MenuIcon) return null;
        
        return (
            <ListItem key={button.text} disablePadding>
                <ListItemButton onClick={button.onClickFunction}>
                    <ListItemIcon>
                        <MenuIcon />
                    </ListItemIcon>
                    <ListItemText primary={button.text} />
                </ListItemButton>
            </ListItem>
        )
    })}
</List>

方案二:非空断言(仅当确定所有图标都在Map中时使用)

<List>
    {generalButtons.map((button) => {
        // 用!断言值不为undefined
        const MenuIcon = menuIconToComponentMap.get(button.icon)!;
        
        return (
            <ListItem key={button.text} disablePadding>
                <ListItemButton onClick={button.onClickFunction}>
                    <ListItemIcon>
                        <MenuIcon />
                    </ListItemIcon>
                    <ListItemText primary={button.text} />
                </ListItemButton>
            </ListItem>
        )
    })}
</List>

这样就能让TypeScript确认MenuIcon是有效的React组件,消除类型错误。

内容的提问来源于stack exchange,提问作者András Krausz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:03:31