I am trying to work out how to create a dot notation component and everything I've found on SO and Google doesn't appear to work in the way that I am expecting.
I have the following code for two components, at the moment its all in one file
const ThreeDotMenu : any = ({children}) => {
return (
<>
<ul className='absolute bg-primary-light text-white'>
{children}
</ul>
</>
)
}
const Item : React.FC<DefaultProps> = ({children}) => {
return (
<li>{children}</li>
)
}
ThreeDotMenu.Item = Item;
export default ThreeDotMenu;
And I am using it as follows:
<ThreeDotMenu>
<ThreeDotMenu.Item>item</ThreeDotMenu.Item>
<ThreeDotMenu.Item>item 2</ThreeDotMenu.Item>
</ThreeDotMenu>
This is working fine except the parent component isn't type instead I am using any as the type.
I am now trying to type it by changing the declaration to be:
const ThreeDotMenu : React.FC<DefaultProps> = ({children}) => {}
The component itself is happy, however the declaration where I do ThreeDotMenu.Item = Item
now throws an error with the following:
Property 'Item' does not exist on type FC
And my DefaultProps
is typed as follows:
export interface DefaultProps {
children: Array<React.ReactNode>|React.ReactNode
}
CodePudding user response:
You can work around this by having a .Menu
component that acts as the parent component.
import React from 'react';
const Menu: React.FC<DefaultProps> = ({children}: any) => {
return (
<>
<ul className='absolute bg-primary-light text-white'>
{children}
</ul>
</>
)
}
const Item: React.FC<DefaultProps> = ({children}) => {
return (
<li>{children}</li>
)
}
const ThreeDotMenu = {Menu, Item}
export default ThreeDotMenu
<ThreeDotMenu.Menu>
<ThreeDotMenu.Item>item</ThreeDotMenu.Item>
<ThreeDotMenu.Item>item 2</ThreeDotMenu.Item></ThreeDotMenu.Menu>
If you want to use the parent without the dot, you can just let the compiler figure the types out instead of giving explicit types.
const ThreeDotMenu = ({ children }) => {
return (
<>
<ul className="absolute bg-primary-light text-white">{children}</ul>
</>
);
};
const Item = ({ children }) => {
return <li>{children}</li>;
};
ThreeDotMenu.Item = Item;
export default function App() {
return (
<ThreeDotMenu>
<ThreeDotMenu.Item>item</ThreeDotMenu.Item>
<ThreeDotMenu.Item>item 2</ThreeDotMenu.Item>
</ThreeDotMenu>
);
}
CodePudding user response:
The simplest way is to not use React.FC
, as suggested in @nullptr's answer.
If you really want to use it, you can add an intersection with your extra properties that you assign later on:
const ThreeDotMenu: React.FC<DefaultProps> & {
Item: typeof Item
}