Leo Jiang
Leo Jiang

Reputation: 26085

React.PropsWithChildren with no props other than `children`?

I have a component with no props other than children, i.e.:

function Foo({ children }: React.PropsWithChildren<>) {}

React.PropsWithChildren requires an argument. If I do React.PropsWithChildren<{}>, Eslint produces Don't use `{}` as a type. `{}` actually means "any non-nullish value"..

I'm using this for the empty object type:

type EmptyObj = { [k: string]: never };

However, React.PropsWithChildren<EmptyObj> causes:

Type '{ children: Element; }' is not assignable to type 'EmptyObj'.
  Property 'children' is incompatible with index signature.
    Type 'Element' is not assignable to type 'never'.

What should I pass to React.PropsWithChildren?

Edit:

I know I can just do:

function Foo({ children }: { children?: React.ReactNode }) {}

However, I'm using React.PropsWithChildren throughout the codebase, so I'd prefer to keep it consistent.

Upvotes: 29

Views: 22995

Answers (5)

rafaelbiten
rafaelbiten

Reputation: 6240

I was in the same situation and decided to go with:

PropsWithChildren<unknown>

Update:

See Jorrit's comment below, but React is making that the default for PropsWithChildren, which is now defined as type PropsWithChildren<P = unknown> .... That means we can simplify the example below to:

const MyComponent = ({ children }: PropsWithChildren) => { /* ... */ }

We're declaring a component that accepts children, but we don't know (or don't care) about other props it may have.

Example:

const MyComponent = ({ children }: PropsWithChildren<unknown>) => { /* ... */ }

// ...

<MyComponent>
  <span>children</span>
</MyComponent>

Why not the FC type?

The use of the FC type is discouraged. You can read more about it in this PR: https://github.com/facebook/create-react-app/pull/8177

Upvotes: 29

jonathanopenshaw
jonathanopenshaw

Reputation: 35

Do you know and have you defined the types of children that the FC will be taking? If so, could you not just have a union type that is passed in as the child prop value?

type FooChildren = ChildTypeOne | ChildTypeTwo | ChildTypeThree;
type FooProps = { children?: FooChildren[] };

function Foo({ children }: React.PropsWithChildren<FooProps>) {}

Also, isn't ReactChildren an interface itself? Why not use that in the function argument?

Upvotes: 1

Andrei Kovalev
Andrei Kovalev

Reputation: 959

The solution is:

function Foo({ children }: React.PropsWithChildren<Record<never, any>>) {}

If eslint warns you about type any use Record<never, never> instead.

Upvotes: 28

Christian Ivicevic
Christian Ivicevic

Reputation: 10885

You can just leverage the FC type as follows:

const Foo: FC = ({ children }) => {
    return <div>{children}</div>;
};

If you really want to stick to PropsWithChildren, then use PropsWithChildren<unknown> instead of PropsWithChildren<{}>. The warning you get comes from typescript-eslint and can be turned off for those cases as another option.

Upvotes: 6

Dennis Vash
Dennis Vash

Reputation: 53874

Looking at how React.FC<> implemented you can try:

interface WrapperProps<> {}

function App(props: React.PropsWithChildren<WrapperProps>) {
  return <div>{props.children}...</div>;
}

Upvotes: 0

Related Questions