#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']
, это работает и для функциональных компонентов.