Morten Barklund
Morten Barklund
Lead Frontend Developer, React expert, accessibility advocate, ultrarunner, and board game enthusiast. Also, I simply ❤️  corgis!
Jan 5, 2023 6 min read

Returning children in React + Typescript

In this blog post, we’ll go over the topic of returning the children property directly from a React component discussing why you would want to do that, what issues you can run into when introducing TypeScript, and how we can get around it.


Let’s say we’re tasked with creating a React component to display a numbered list of pages for a pagination result. You know, those underlined numbers below search results with 1, 2, 3, etc. However, we don’t want the current page to be a link, only the other pages in the list.

That seems like an easy exercise. We are going to need two components, one for the list, PageLinkList, and one for each number in it, PageLink.

Let’s do so in plain JavaScript and React to start with.

function PageLinkList({ numPages, currentPage }) {
  // Create an array like [1,2,3,...,numPages].
  const pageLinks = Array.from({ length: numPages }).map((v, k) => k);
  return (
    <nav>
      {pageLinks.map((page) =>
        <PageLink key={page} link={`?page=${page}`} isLink={page === currentPage}>{page+1}</PageLink>
      )}
    </nav>
  );
}
function PageLink({ isLink, link, children }) {
  return isLink ? <a href={link}>{children}</a> : children;
}

This all seems reasonable, and we can use it to create a nice list of links like this:

function App() {
  return (
    <main>
      <PageLinkList numPages={7} currentPage={2} />
    </main>
  );
}

But we want to use TypeScript of course. React, like any other JavaScript project, becomes so much more pleasant to work with using a nicely typed language such as TypeScript.

So, let’s add some types. The most obvious solution is to do this:

import { PropsWithChildren } from "react";
function PageLink({
  isLink,
  link,
  children
}: PropsWithChildren<{ isLink: boolean; link: string }>) {
  return isLink ? <a href={link}>{children}</a> : children;
}
function PageLinkList({
  numPages,
  currentPage
}: {
  numPages: number;
  currentPage: number;
}) {
  // Create an array like [0,1,2,...,numPages-1].
  const pageLinks = Array.from({ length: numPages }).map((v, k) => k);
  return (
    <nav>
      {pageLinks.map((page) => (
        <PageLink
          key={page}
          link={`?page=${page}`}
          isLink={page !== currentPage}
        >
          {page + 1}
        </PageLink>
      ))}
    </nav>
  );
}

That all looks pretty straight-forward. We type the <PageLink /> component using the React.PropsWithChildren so we can allow any type of child or list of children to be passed to it, and we type all other properties using their primitives.

But this doesn’t work. If you do this, you will see this error where we use the <PageLink /> component:

'PageLink' cannot be used as a JSX component.
  Its return type 'string | number | boolean | ReactFragment | Element | null | undefined' is not a valid JSX element.
    Type 'undefined' is not assignable to type 'Element | null'.

Why is that? Well, that is because we’re returning the children prop directly under some circumstances. And that prop does not qualify as a proper return value.

That is because the PropsWithChildren interface types the children property as ReactNode, which in turn is defined as:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined

Note that this includes undefined, which is what TypeScript complains about (for now..!). Components aren’t allowed to return undefined, but rather null in case they shouldn’t render anything.

So what can we do about that?


There are three posible fixes.

  1. We can define the children property in a way, where it doesn’t allow undefined.
  2. We can return null in case the children property is undefined and we want to return it as-is.
  3. We can make sure to wrap the children property in a valid JSX element.

Option 1 is a bit tricky to do. It would require manually defining the type for children which isn’t very forwards-compatible. When we use the built-in PropsWithChildren interface, we’re guaranteed it follows the internal type system of React going forwards, but if we circumvent that, we can’t be sure it still does that in the future.

Options 2 seems a lot more approachable. We can just make sure to return null in case children is undefined, quite easily like so:

  return isLink ? <a href={link}>{children}</a> : (children ?? null);

Here we use nullish coalescing to return null in case children is undefined (or null).

Frustratingly, that still doesn’t work. Now, we get another TypeScript error:

'PageLink' cannot be used as a JSX component.
  Its return type 'string | number | boolean | ReactFragment | Element | null' is not a valid JSX element.
    Type 'string' is not assignable to type 'ReactElement<any, any>'.

It turns out, undefined isn’t the only possible value of the children property, that we aren’t allowed to return directly from a component.

We could dive further into this and handle the other possible values, but let’s turn to option 3 instead. Returning a JSX element no matter what. We can wrap the children property in a React fragment like so:

function PageLink({
  isLink,
  link,
  children
}: PropsWithChildren<{ isLink: boolean; link: string }>) {
  return isLink ? <a href={link}>{children}</a> : <>{children}</>;
}

And that’s it. This just works with no quirks or anything else required. We return a simple React fragment wrapping the property: <>{children}</>.

Why does this work? Well, that’s quite simple. The children property is typed as anything that is allowed to be put inside a JSX node, so we can of course put it inside a fragment node, which is a valid JSX node. And we can return a fragment from a component, because it is a valid JSX node.

You can play around with this example in TypeScript Playground, or in the CodeSandbox that you also see below:

Note: If you are using ESLint, you might have a rule prohibiting “useless” fragments (react/jsx-no-useless-fragment) , which will (somewhat erroneously) mark this use as a match for that rule.

You can get around that by telling ESLint to ignore this instance:

function PageLink({
  isLink,
  link,
  children
}: PropsWithChildren<{ isLink: boolean; link: string }>) {
  // eslint-disable-next-line react/jsx-no-useless-fragment -- required for valid return type
  return isLink ? <a href={link}>{children}</a> : <>{children}</>;
}

And now even you should be good to go.

To an extent, this is a useless fragment, as it has no practical function, but will actually appear in the resulting JavaScript when the TypeScript is compiled. So it’s an extra JavaScript wrapper to make TypeScript happy. This does introduce a tiny overhead, but that’s probably negligible in almost all applications.


Returning the children property directly from a React component is sometimes a useful tool, but TypeScript makes it a bit tricky to do. The solution however is surprisingly simple with only the tiniest of downsides.

If you need to return the children property directly in a React component when using TypeScript, make sure to wrap it in a fragment like so: <>{children}</>.