'Generic composable component props for interface

I'm working on a functional component that composes other components that are passed in. My interface looks like this:

interface IMyComponentProps {
  ...
  /** What custom component to use */
  elem?: React.ReactNode;
  /** Custom component props */
  elemProps?: any;
}

I'm wondering if there is a way I can make this a generic instead of using any for the elemProps propery. Is there a way to get the props of whatever elem happens to be?



Solution 1:[1]

I thin this is what you want:

interface IMyComponentProps<T extends React.ComponentType<any>> {
  /** What custom component to use */
  elem: T;
  /** Custom component props */
  elemProps: React.ComponentProps<T>;
}

ReactComponent<Props> is the type of a component that you would pass props to to render. And ComponentProps<T> is the type that returns the props from a ReactComponent.

Testing this, it seems to works like you expect:

function Wrapper<T extends React.ComponentType<any>>({elem, elemProps}: IMyComponentProps<T>) {
    const Elem = elem
    return <Elem {...elemProps} />
}

function Test(props: { a: number, b: string }) {
    return <></>
}

// works
const testWrapper = <Wrapper elem={Test} elemProps={{ a: 1, b: 'hello' }} />

// error as expected
const testWrapperError = <Wrapper elem={Test} elemProps={{ a: 1, c: 'hello' }} />

Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Wayne