2

Let's say we have a component Foo that renders props.children and another component Bar. Both modules export a props interface.

Is there a way to enforce that Foo's children can be only of type Bar?

Ideally we could accomplish this with TypeScript at build-time.

Example:

import { createElement, FC, ReactNode } from 'react';
import { Bar, BarProps } from '../Bar';

export interface FooProps {
  children?: ReactNode; // this works
  // children?: ReactNode<BarProps>; // nope
  // children?: Bar; // nope
}

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

Note: we are not using PropTypes

Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115
  • Out of curiosity, why do you need a strong requirement on props.children? – ShadowMitia Jul 01 '20 at 14:34
  • Our internal component library needs to abide by a fairly strict UX specification/design guide. A contrived example would be that Table shouldn't be allowed to be a child of a Dropdown component. – Jonathan.Brink Jul 01 '20 at 14:46

1 Answers1

0

Try this (reference)

export interface FooProps {
  children?: React.ReactElement<BarProps> | React.ReactElement<BarProps>[]
}
Stutje
  • 745
  • 6
  • 21
  • I think you meant `React.ReactElement[]`? – ShadowMitia Jul 01 '20 at 15:15
  • 1
    If the children of `Foo` need to be completely strict to accepting a component with the type signature of `Bar` this will not work. Try rendering a simple `h1` element as children to `Foo` (`

    Hello

    `) and you will see that the compiler doesn't even complain.
    – subashMahapatra Jul 01 '20 at 15:23
  • I tried this out, and I'm still able to pass non-Bar components in as children of Foo with no compiler warnings/errors – Jonathan.Brink Jul 01 '20 at 15:28
  • If you read further in the reference above you'll see "Will get rid of the error, but it won't be type-checking the children properly", I think this is the closest you will get for restricting in the FooProps interface. Maybe throw an error or filter wrong types at the beginning of your component will do the trick? – Stutje Jul 02 '20 at 07:34