I run into a trouble with trying to allow only specific children to be passed to a component.
Here are my components, HeaderLink
import { SFC, ReactElement } from "react";
import "./Header.scss";
export interface IHeaderLinkProps {
url: string;
label: string;
}
const HeaderLink: SFC<IHeaderLinkProps> = ({ url, label }): ReactElement => (
<li className="nav-item">
<a href={url}>{label}</a>
</li>
);
export default HeaderLink;
and Header
import { SFC, ReactElement } from "react";
import { IHeaderLinkProps } from "./HeaderLink";
import "./Header.scss";
interface IHeaderProps {
children: ReactElement<IHeaderLinkProps> | ReactElement<IHeaderLinkProps>[];
}
const Header: SFC<IHeaderProps> = ({ children }): ReactElement => {
return (
<header className="header">
<div className="container">
<div className="row">
<div className="col">
<img
className="header__logo"
src={"/logo.png"}
alt="monqrime-logo"
/>
<ul className="header__nav">{children}</ul>
</div>
</div>
</div>
</header>
);
};
So the problem is that I want to allow only HeaderLink components to be passed as children to the Header, but my current solution still allows me to put everything as a children.
Children is a special prop that allows us to pass in any type of element. It could be a number, a string, a boolean, an array of elements or even another component.
children is a special prop, automatically passed to every component, that can be used to render the content included between the opening and closing tags when invoking a component. These kinds of components are identified by the official documentation as “boxes”.
React.Children.toArrayReturns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
I would probably declare IHeaderProps.children
as:
children: React.ReactElement<IHeaderProps> | React.ReactElement<IHeaderProps>[];
To account for the possibility of having both a single and multiple children.
In any case, what you want is not possible. See:
How do I restrict the type of React Children in TypeScript, using the newly added support in TypeScript 2.3?
React Component children typecheck with typescript
What you could do instead is declare a prop, let's say links?: IHeaderLinkProps[]
, to pass down the props you need to create those HeaderLink
s, rather than their JSX, and render them inside Header
:
interface IHeaderProps {
children?: never;
links?: IHeaderLinkProps[];
}
...
const Header: React.FC<IHeaderProps> = ({ links }) => {
return (
...
<ul className="header__nav">
{ links.map(link => <HeaderLink key={ link.url } { ...link } />) }
</ul>
...
);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With