我只想允许特定组件作为子组件。例如,假设我有一个菜单组件,它应该只包含
MenuItem
作为子组件,如下所示:
<Menu>
<MenuItem />
<MenuItem />
</Menu>
因此,当我尝试将另一个组件作为子组件时,我希望 Typescript 在 IDE 中抛出错误。有人警告我,我只能在孩子时期使用
MenuItem
。例如在这种情况下:
<Menu>
<div>My item</div>
<div>My item</div>
</Menu>
此线程几乎相似,但不包含 TypeScript 解决方案。我想知道是否可以使用 TypeScript 类型和接口来解决这个问题。在我想象的世界中,它看起来像这样,但是类型检查当然不起作用,因为子组件具有
Element
类型:
type MenuItemType = typeof MenuItem;
interface IMenu {
children: MenuItemType[];
}
const MenuItem: React.FunctionComponent<IMenuItem> = ({ props }) => {
return (...)
}
const Menu: React.FunctionComponent<IMenu> = ({ props }) => {
return (
<nav>
{props.children}
</nav>
)
}
const App: React.FunctionComponent<IApp> = ({ props }) => {
return (
<Menu>
<MenuItem />
<MenuItem />
</Menu>
)
}
有没有办法用 Typescript 来实现这一点?喜欢用仅与特定组件相关的东西来扩展 Element 类型吗?
或者确定子组件是特定组件的实例的好方法是什么?无需添加查看子组件 displayName 的条件。
为此,您需要从子组件(最好也是父组件)中提取 props 接口,并以这种方式使用它:
interface ParentProps {
children: ReactElement<ChildrenProps> | Array<ReactElement<ChildrenProps>>;
}
所以在你的情况下它看起来像这样:
interface IMenu {
children: ReactElement<IMenuItem> | Array<ReactElement<IMenuItem>>;
}
const MenuItem: React.FunctionComponent<IMenuItem> = ({ props }) => {
return (...)
}
const Menu: React.FunctionComponent<IMenu> = ({ props }) => {
return (
<nav>
{props.children}
</nav>
)
}
尽管有上述答案,但你不能对孩子这样做。您可以在组件的开发版本中执行运行时检查,但无法使用 TypeScript 类型执行此操作 — 至少目前还不能。
来自 TypeScript 问题 #18357:
现在除了在
命名空间内指定ElementChildrenAttribute
之外,无法指定子代表示是什么。它与子项的 React 表示紧密结合,这意味着子项是 props 的一部分。这使得无法对具有单独存储子项的实现的子项启用类型检查,例如 https://github.com/dfilatov/vidom/wiki/Component-properties。JSX
并请注意,它在 #21699 中被引用,基本上,围绕
ReactElement
的可能破坏性更改也可能使执行此操作成为可能。
现在,您所能做的就是运行时检查,或接受 props (或 props 数组)和可选的组件函数(在您的情况下,您知道它是
MenuItem
)并在组件中创建元素。
还有一个问题是你是否应该这样做。为什么我不能编写一个返回
MenuItem
的组件,而不是直接使用 MenuItem
? :-)
我一直在研究和记录,我可能刚刚找到了解决方案。
const childrenWithProps = React.Children.map(props.children, (child) => {
console.log(child.type)
if (React.isValidElement(child) &&
((child.type as any)._payload.value.name === NavLinks.name)) {
return cloneElement(child, { ref: menuRef });
}
throw new Error(`Navbar solo puede recibir ${NavLinks.name} o NavbarIcons como children.`);
});
在 vscode 中,属性 _payload 无法从 child.type 访问,因此我将其设置为 any,这样 IDE 就不会抛出错误。