JaffParker
JaffParker

Reputation: 716

How to reference a component's props in React?

I have a component that can accept another component as a prop. Whatever other props it has, it also passes them down to the child component. That's what it looks like:

interface FormGroupProps extends BasicInputProps<any> {
  label: string
  name: string
  Component: ComponentType<BasicInputProps<any>>
}

export const FormGroup: SFC<FormGroupProps> = ({
  label,
  Component,
  ...props
}) => (
  <RBSFormGroup>
    <Label>{label}</Label>
    <Component {...props} />
  </RBSFormGroup>
)

You can see that in FormGroupProps I tell TS that Component will accept only props of a certain type. That is not ideal, because sometimes I need to pass components that don't necessarily match that signature.

I could potentially just write ComponentType<any>, but that's too loose. I'd like to be able to write something like ComponentType<Component['props']>, but as far as I know there's no such thing.

Is there a way to reference a components props type? Or do I need to pass a generic type manually to achieve that?

Upvotes: 3

Views: 6529

Answers (1)

Dylan Walker
Dylan Walker

Reputation: 1127

New typings introduced to @types/react in response to React 16.6 include the following types:

type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
    T extends JSXElementConstructor<infer P>
        ? P
        : T extends keyof JSX.IntrinsicElements
            ? JSX.IntrinsicElements[T]
            : {};

type ComponentPropsWithRef<T extends ElementType> =
    T extends ComponentClass<infer P>
        ? PropsWithoutRef<P> & RefAttributes<InstanceType<T>>
        : PropsWithRef<ComponentProps<T>>;

type ComponentPropsWithoutRef<T extends ElementType> = PropsWithoutRef<ComponentProps<T>>;

Which reference the types of a component's props. You should be able to achieve your desired interface using one of these new types:

interface FormGroupProps {
    label: string;
    name: string;
    Component: React.ComponentProps<typeof Component>;
}

This is super handy if you want to avoid exporting prop interfaces all over the place, or for extracting props interfaces from libraries which don't export them. Also, unlike Component['props'], it also works for functional components.

Upvotes: 3

Related Questions