Как ссылаться на реквизиты компонента в React?

#reactjs #typescript

#reactjs #typescript

Вопрос:

У меня есть компонент, который может принимать другой компонент в качестве реквизита. Какими бы другими реквизитами он ни обладал, он также передает их дочернему компоненту. Вот как это выглядит:

 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>
)
  

Вы можете видеть, что в FormGroupProps я сообщаю TS, что компонент будет принимать только реквизиты определенного типа. Это не идеально, потому что иногда мне нужно передавать компоненты, которые не обязательно соответствуют этой подписи.

Потенциально я мог бы просто написать ComponentType<any> , но это слишком свободно. Я хотел бы иметь возможность написать что-то вроде ComponentType<Component['props']> , но, насколько я знаю, такой вещи не существует.

Есть ли способ ссылаться на тип реквизита компонента? Или мне нужно передать универсальный тип вручную, чтобы достичь этого?

Комментарии:

1. немного запутался, не понял, какие типы компонентов вы хотите принять

2. Интересно. Единственное, что я могу придумать, чтобы попробовать, — это новая версия React.ComponentProps<typeof Component> , хотя ожидать, что она будет работать для универсального элемента, может потребовать слишком многого.

3. @AlexandrZavalii Я хочу принимать все типы компонентов, но иметь возможность ограничивать реквизиты только реквизитами этого компонента

4. @DylanWalker это работает! Если вы опубликуете это как ответ, я приму его

5. Рад это слышать! Не думал, что это будет достаточно мощным для данного конкретного случая, но приятно получить некоторое подтверждение обратного 🙂

Ответ №1:

Новые типы, введенные в @types/react в ответ на React 16.6, включают следующие типы:

 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> amp; RefAttributes<InstanceType<T>>
        : PropsWithRef<ComponentProps<T>>;

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

Которые ссылаются на типы реквизитов компонента. Вы должны быть в состоянии достичь желаемого интерфейса, используя один из этих новых типов:

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

Это очень удобно, если вы хотите избежать повсеместного экспорта prop-интерфейсов или для извлечения props-интерфейсов из библиотек, которые их не экспортируют. Кроме того, в отличие от Component['props'] , это работает и для функциональных компонентов.