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

如何在TypeScript中使用Ant Design构建动态菜单?

解决Ant Design TypeScript动态菜单类型错误问题

在使用TypeScript构建Ant Design动态菜单组件时,参考JavaScript方案后遇到类型报错:item仅被识别为拥有className, key, style属性的类型,导致icon={item?.icon}和{item?.label}处构建失败。

问题原因

Ant Design的MenuProps['items']是一个联合类型,包含了菜单项、子菜单、分割线等多种类型,TypeScript默认会推断为所有类型的交集——仅保留所有类型共有的className, key, style属性,因此无法识别icon、label这些专属菜单项的属性。

解决方案

以下是几种可行的修复方式:

方式一:显式指定菜单项类型

从antd导入MenuItemProps,将菜单数组的类型指定为MenuItemProps[],明确告诉TypeScript这是标准菜单项的数组:

import { useState, useEffect } from 'react';
import { Menu, type MenuProps, type MenuItemProps } from 'antd';
// 导入你的图标组件
import IconSetting from './icons/IconSetting';
import IconUpgrade from './icons/IconUpgrade';
import IconHelp from './icons/IconHelp';
import IconAbout from './icons/IconAbout';
import IconImport from './icons/IconImport';
import IconExport from './icons/IconExport';

function CustomAppBarMenu() {
    // 显式指定类型为MenuItemProps数组
    const [menuItems, setMenuItems] = useState<MenuItemProps[]>([]);

    const main_window_menu_items: MenuItemProps[] = [
        {
            key: 'setting',
            label: 'Setting',
            icon: <IconSetting />,
        },
        {
            key: 'upgrade',
            label: 'Upgrade',
            icon: <IconUpgrade />,
            disabled: true,
        },
        {
            key: 'help',
            label: 'Help',
            icon: <IconHelp />,
        },
        {
            key: 'about',
            label: 'About',
            icon: <IconAbout />,
        },
    ];

    const edit_menu_items: MenuItemProps[] = [
        {
            key: 'import',
            label: 'Import',
            icon: <IconImport />,
        },
        {
            key: 'export',
            label: 'Export',
            icon: <IconExport />,
        },
    ];

    const handleMenuClick: MenuProps['onClick'] = ({ key }) => {
        console.log(`Click on item ${key}`);
    };

    useEffect(() => {
        // 假设appWindow是已定义的变量
        if (appWindow.label === 'main') {
            setMenuItems(main_window_menu_items);
        } else if (appWindow.label === 'edit') {
            setMenuItems(edit_menu_items);
        }
        // 添加依赖项避免无限循环
    }, [appWindow.label]);

    return (
        <Menu onClick={handleMenuClick}>
            {menuItems?.map((item) => (
                <Menu.Item key={item.key} icon={item.icon}>
                    {item.label}
                </Menu.Item>
            ))}
        </Menu>
    );
}

方式二:使用Menu组件的items属性(更简洁)

Ant Design的Menu组件支持直接通过items属性传入菜单配置,无需手动渲染Menu.Item,这种方式下TypeScript能自动识别类型:

import { useState, useEffect } from 'react';
import { Menu, type MenuProps } from 'antd';
// 导入你的图标组件
import IconSetting from './icons/IconSetting';
import IconUpgrade from './icons/IconUpgrade';
import IconHelp from './icons/IconHelp';
import IconAbout from './icons/IconAbout';
import IconImport from './icons/IconImport';
import IconExport from './icons/IconExport';

function CustomAppBarMenu() {
    const [menuItems, setMenuItems] = useState<MenuProps['items']>([]);

    const main_window_menu_items: MenuProps['items'] = [
        {
            key: 'setting',
            label: 'Setting',
            icon: <IconSetting />,
        },
        {
            key: 'upgrade',
            label: 'Upgrade',
            icon: <IconUpgrade />,
            disabled: true,
        },
        {
            key: 'help',
            label: 'Help',
            icon: <IconHelp />,
        },
        {
            key: 'about',
            label: 'About',
            icon: <IconAbout />,
        },
    ];

    const edit_menu_items: MenuProps['items'] = [
        {
            key: 'import',
            label: 'Import',
            icon: <IconImport />,
        },
        {
            key: 'export',
            label: 'Export',
            icon: <IconExport />,
        },
    ];

    const handleMenuClick: MenuProps['onClick'] = ({ key }) => {
        console.log(`Click on item ${key}`);
    };

    useEffect(() => {
        if (appWindow.label === 'main') {
            setMenuItems(main_window_menu_items);
        } else if (appWindow.label === 'edit') {
            setMenuItems(edit_menu_items);
        }
    }, [appWindow.label]);

    // 直接通过items属性传入,无需手动映射Menu.Item
    return <Menu onClick={handleMenuClick} items={menuItems} />;
}

方式三:类型断言(临时方案)

如果需要保留手动渲染Menu.Item的方式,也可以通过类型断言告诉TypeScript当前item是标准菜单项:

// 在map的时候添加类型断言
{menuItems?.map((item) => {
    const menuItem = item as MenuItemProps;
    return (
        <Menu.Item key={menuItem.key} icon={menuItem.icon}>
            {menuItem.label}
        </Menu.Item>
    );
})}

额外注意

  • 别忘了给useEffect添加依赖项[appWindow.label],避免组件无限重渲染。
  • 确保图标组件的导入路径正确。

内容的提问来源于stack exchange,提问作者Hellagur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 00:52:44