Using the React <code>children</code> prop with TypeScript
Tags: typescript, react, webdev
Published: 2023-01-05 15:45:21

**Written by [Ohans Emmanuel](https://blog.logrocket.com/author/ohansemmanuel/)✏️**

Properly typing the `children` prop in React can pose some difficulty at first. If you try typing them as specific JSX types, you may run into issues rendering the child components. There’s also the problem with the paradox of choice, as there are multiple available options to type the children prop. This may lead to decision fatigue. 

In this article, I’ll share my recommended solutions to this, based on experience. For completeness, I’ll also share some other, arguably relevant approaches. 

_Jump ahead:_

*   [Children in JSX](#children-jsx)
*   [Supported children types](#supported-children-types)
*   [Using the `PropsWithChildren` type](#using-propswithchildren-type)
*   [Explicitly using the `ReactNode` type](#explicitly-using-reactnode-type)
*   [Using the `FunctionComponent` (or `FC`) type](#using-functioncomponent-fc-type)
*   [Using the `Component` type for class components](#using-component-type-class-components)

Let’s get started.

## Children in JSX <a name="children-jsx">

When you write a JSX expression with opening and closing tags, the content passed between them is referred to as their “child”. ![Children passed between the opening and closing tag of your JSX expression](https://blog.logrocket.com/wp-content/uploads/2022/12/children-passed-between-opening-closing-tag-jsx-expression.png)

Consider the following contrived example:

```javascript
<Border> Hey, I represent the JSX children! </Border>
```

In this example, the literal string `Hey, I represent the JSX children!` refers to the child rendered within `Border`. 

Conversely, to gain access to the content passed between JSX closing and opening tags, React passes these in a special prop: `props.children` 

For example, `Border` could receive the `children` prop as follows:

```javascript
const Border = ({children}) => {
   return <div style={{border: "1px solid red"}}>
      {children}
   </div>
}
```

`Border` accepts the `children` prop, then renders the `children` within a `div` with a border style of `1px solid red`. 

This is the basic usage of the `children` prop, i.e., to receive and manipulate the content passed within the opening and closing tags of a JSX expression.

## Supported children types

Strictly speaking, there’s a handful of supported content types that can go within the opening and closing tags of your JSX expression. Below are some of the most used ones:

### Strings

Literal strings are valid children types, as shown below:

```typescript
<YourComponent> This is a valid child string </YourComponent />
```

Note that in `YourComponent`, `props.children` will simply be the string `This is a valid child string`.

### JSX

You can equally pass other JSX elements as valid children. This is usually helpful when composing different nested components. Below’s an example:

```typescript
<Wrapper>
  <YourFirstComponent />
  <YourSecondComponent />
</Wrapper>
```

It is also completely acceptable to mix children types, as shown below:

```typescript
<Wrapper>
  I am a valid string child
  <YourFirstComponent />
  <YourSecondComponent />
</Wrapper>
```

### JavaScript expressions

Expressions are equally valid children types, as shown below:

```typescript
<YourFirstComponent> {myScopedVariableReference} </YourFirstComponent>
```

Remember that expressions in `JSX` are written in curly braces.

### Functions

Functions are equally valid children types as shown below:

```typescript
<YourFirstComponent> 
  {() => <div>{myScopedVariableReference}</div>} 
</YourFirstComponent>
```

As you can see, the `children` prop can be represented by quite a wide range of data types! Your first inclination might be to type these out manually, like so:

```typescript
type Props = {
  children: string | JSX.Element | JSX.Element[] | () => JSX.Element
}

const YourComponent = ({children} : Props) => {
  return children
}
```

This might seem like a good idea, but it doesn’t fully represent the `children` prop. What about fragments, portals, and ignored render values, such as `undefined`, `null`, `true`, or `false` ? 

A full representation may look something like this:

```typescript
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;

interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

type Props = {
  children: ReactNode
}

// source: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d076add9f29db350a19bd94c37b197729cc02f87/types/react/index.d.ts
```

See the extended types for [ReactPortal](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d076add9f29db350a19bd94c37b197729cc02f87/types/react/index.d.ts#L190) and [ReactElement](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d076add9f29db350a19bd94c37b197729cc02f87/types/react/index.d.ts#L146). Do they look complex? There’s a good chance they do. 

The point I’m trying to make is, in practice, you don’t want to type the `children` prop manually. Instead, I suggest using the officially supported types discussed below.

## Using the `PropsWithChildren` type <a name="using-propswithchildren-type">

The `React.PropsWithChildren` type takes your component prop and returns a union type with the `children` prop appropriately typed. No extra work from you needed. 

In practice, here’s [the definition](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/d076add9f29db350a19bd94c37b197729cc02f87/types/react/index.d.ts#L822) for the `PropsWithChildren` type:

```typescript
type PropsWithChildren<P> = P & { children?: ReactNode };
```

![How the propsWithChildren type works](https://blog.logrocket.com/wp-content/uploads/2022/12/how-propswithchildren-type-works.png) Assuming you had a component `Foo` with props `FooProps`:

```typescript
type FooProps = {
  name: 'foo'
}

export const Foo = (props: FooProps) => {
    return null
}
```

You can go ahead and introduce the `children` prop as follows:

```typescript
import { PropsWithChildren } from 'react'

type FooProps = {
  name: 'foo'
}

export const Foo = (props: PropsWithChildren<FooProps>) => {
    return props.children
}
```

When you pass `PropsWithChildren` to your component prop `FooProps`, you get the `children` prop internally typed. 

In most cases, this is the recommended way to go about typing the `children` prop because it requires less boilerplate and the `children` prop is implicitly typed.

## Explicitly using the `ReactNode` type <a name="explicitly-using-reactnode-type">

In cases where you must explicitly type the `children` prop, you can go ahead and use the `ReactNode` type. 

Remember the definition for the `PropsWithChildren` type:

```typescript
type PropsWithChildren<P> = P & { children?: ReactNode };
```

![The propsWithChildren type leverages the reactNode type](https://blog.logrocket.com/wp-content/uploads/2022/12/propswithchildren-type-leverages-reactnode-type.png) Instead of relying on `PropsWithChildren`, you can also type the `children` prop directly:

```typescript
import { ReactNode } from 'react'

type FooProps = {
  name: 'foo'
  // look here 👇
  children: ReactNode
}

export const Foo = (props: FooProps) => {
    return props.children
}
```

## Using the `FunctionComponent` (or `FC`) type <a name="using-functioncomponent-fc-type">

The `FunctionComponent` generic interface may also be used to appropriately type the `children` prop. Internally, this interface relies on `PropsWithChildren`. 

Here’s how you’d use this:

```typescript
import { FunctionComponent } from 'react'

type FooProps = {
  name: 'foo'
}

export const Foo: FunctionComponent<FooProps> = (props) => {
    return props.children
}
```

Note that the `FC` type is an alias for `FunctionComponent` for ease. Their usages are similar, as shown below:

```typescript
import { FC } from 'react'

type FooProps = {
  name: 'foo'
}

export const Foo: FC<FooProps> = (props) => {
    return props.children
}
```

## Using the `Component` type for class components <a name="using-component-type-class-components">

Most modern React codebases no longer use class components, except in specific use cases. 

If you find yourself needing to type the `children` prop in a class component, leverage the `Component` prop, as shown below:

```typescript
import { Component } from 'react'

type FooProps = {
  name: 'foo'
}

class Foo extends Component<FooProps> {
  render() {
    return this.props.children
  }
}
```

Similar to the `FunctionComponent` interface and its `FC` alias, the `Component` type automatically includes the `children` prop.

## Conclusion

Where possible, use the `PropsWithChildren` type, but don’t be afraid to type the `children` prop directly as well, whether that’s in a class or functional component.

---
## Cut through the noise of traditional React error reporting with LogRocket

[LogRocket](https://lp.logrocket.com/blg/react-signup-issue-free) is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications.

[![LogRocket signup](https://firebasestorage.googleapis.com/v0/b/logrocket-com/o/react-image.png?alt=media&token=e3f647c1-5b41-4980-b096-5d90e6ba4295)](https://lp.logrocket.com/blg/react-signup-general)

[LogRocket](https://lp.logrocket.com/blg/react-signup-issue-free) automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.

Focus on the React bugs that matter — [try LogRocket today](https://lp.logrocket.com/blg/react-signup-issue-free).