Unsafe 'PropsWithChildren' Utility type in React TypeScript App

Muhammad A Faishal - Jul 15 '23 - - Dev Community

As React developer, we are all familiar with creating components, whether as classes or functions, to add features to web pages.

One of the common cases in React is a component that has JSX Children. When you want to nest content inside a JSX tag, the parent component will receive that content in a prop called children.

For instance, the Modal component below will receive children prop set to and render it in a wrapper div.

// React JavaScript

function Modal(props) {
  const { children } = props;

  return <div className="modal">{children}</div>;
}

function Page() {
  return (
    <Modal>
      <title>Submit Form</title>
      <form onSubmit={handleSubmit}>
        <input type="text" />
        <input type="submit" />
      </form>
    </Modal>
  );
}
Enter fullscreen mode Exit fullscreen mode

If it wants to be converted to TypeScript, most of developers use PropsWithChildren utility type from @types/react package.

// React TypeScript

import type { PropsWithChildren } from "react";

// props: {
//    children?: React.ReactNode;
// }
function Modal(props: PropsWithChildren<{}>) {
  const { children } = props;

  return <div className="modal">{children}</div>;
}

function Page() {
  return (
    <Modal>
      <title>Submit Form</title>
      <form onSubmit={handleSubmit}>
        <input type="text" />
        <input type="submit" />
      </form>
    </Modal>
  );
}
Enter fullscreen mode Exit fullscreen mode

It helps TypeScript understand that the component should have the children prop.

Problems

Sounds good so far, right? But here's where things get weird.

Let me highlight the code.

// props: {
//    children?: React.ReactNode; ❌
// }
Enter fullscreen mode Exit fullscreen mode
// Unexpected ❌

import type { PropsWithChildren } from "react";

// props: {
//    children?: React.ReactNode;
// }
function Modal(props: PropsWithChildren<{}>) {
  const { children } = props;

  return <div className="card">{children}</div>;
}

function Page() {
  return <Modal />;
}
Enter fullscreen mode Exit fullscreen mode

The children is supposed to be required. That means we must provide children when using Modal component. But, guess what? It becomes optional! Rendering Modal component without children is now even possible 😨.

Let's check what's inside PropsWithChildren. Here it is referring to @types/react Github.

type PropsWithChildren<P = unknown> = P & { children?: ReactNode | undefined };
Enter fullscreen mode Exit fullscreen mode

Turns out the culprit is @types/react itself 😵.

This little bug might not seem like a big deal at first, but trust me, it can cause some serious problems and mess up with your business logic. And the worst part? Neither React nor TypeScript will show any errors, leaving you scratching your head when things go wrong 😵‍💫.

Solutions

So, what can we do about this? Let's explore some solutions!

1. Never Trust and Always Check "third-party" code

As you know earlier, the culprit is @types/react itself. This is not the first time. Previously, developers had a problem with React.FC. Some of them even posted about it.

TypeScript + React: Why I don't use React.FC
Why you probably shouldn’t use React.FC to type your React components
Why You Should Probably Think Twice About Using React.FC

All those fancy "magic" codes will eventually lose their "magic" over time. So, you should always check what's behind the code.

2. Create your own Utility type

Since the PropsWithChildren from @types/react is not that hard, why don't you create it yourself?

type PropsWithChildren<P = unknown> = P & { children: ReactNode };
Enter fullscreen mode Exit fullscreen mode

PropsWithChildren utility type is for components that have children prop and it's required.

type PropsWithOptionalChildren<P = unknown> = P & { children?: ReactNode };
Enter fullscreen mode Exit fullscreen mode

PropsWithOptionalChildren utility type is for components that have children prop, but it's optional.

It looks reliable and unambiguous. ✅

Conclusion

Remember these tips and you'll save yourself from headaches. I hope these tips come in handy for your projects! ✨

. . . . . . . . . . .
Terabox Video Player