javascriptreactjstypescriptnext.jsheadless-ui

How can I declare type on mapped elements?


I'm getting an error on the className of mapped elements. I believe TS is throwing the error because the map's children (MenuItem) don't have the className type. See the error below.

The mapped elements are part of the headlessui package. I think this is part of the reason I'm having trouble. I'm following this introduction to headlessui: https://headlessui.com/react/menu. This example is the third code sample on that page.

I tried to make the MenuItemProps interface to use on the .map function like this:

links.map((link): MenuButtonInterface => ()

How can I include the className type to the children of the .map function?

ERROR:

Type '{ children: Element; key: string; className: string; }' is not assignable to type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.


Property 'className' does not exist on type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.ts(2322)

import React, { ReactNode } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'

const links = [
    {href: '/home', label: 'Home'},
    {href: '/Test', label: 'Test'},
    {href: '/settings', label: 'Settings'}
]

interface MenuItemProps{
    children: any
    className?: any
    key: any
}

export const MyComponent = () => {
    return(
        <Menu>
            <MenuButton className='data-[active]:bg-blue-500'></MenuButton>
            <MenuItems anchor='bottom'>
                {links.map((link) => (
                    <MenuItem key={link.href} className='block data-[focus]:bg-blue-500'>
                        <a href={link.href}>{link.label}</a>
                    </MenuItem>
                ))}
            </MenuItems>
        </Menu>
    )
}


Solution

  • Use as Prop Directly on MenuItem

    According to the docs you can use the as prop directly in MenuItem to render an a tag and it will allow you to pass the className

    Code will look like this:

    <MenuItem
      key={link.href}
      as="a"
      href={link.href}
      className="block data-[focus]:bg-blue-500"
    
    { link.label }
    </MenuItem>
    

    Hope this helps you.