Как передать в React.forwardRef дженерик в виде названия элемента?
Введение:
Необходимо написать компонент Button с использованием React.forwardRef, но с возможностью выбора отображаемого элемента, как это реализуется в некоторых библиотеках. Например, по умолчанию отображается элемент button, но если я передаю параметр href, то должна отображаться ссылка. Важный момент заключается в том, что мне нужно связать это поведение с ref - по умолчанию ref должен принимать ссылку типа React.Ref<HTMLButtonElement>, но если я передаю через props параметр href, то ref должен принимать ссылку типа React.Ref<HTMLAnchorElement>
Попытки:
Пока не сильно разбираюсь в тонкостях языка, но вот что у меня получилось накидать.
// общие параметры
type CommonProps = {
children: React.ReactNode
variant?: 'plain' | 'tonal' | 'filled' | 'outlined'
justify?: 'start' | 'center' | 'end'
}
type Props<T extends 'a' | 'button' | never> = (
T extends 'button' | 'a'
? T extends 'a'
? CommonProps & { href: string } & React.ComponentPropsWithoutRef<T>
: CommonProps & { href?: never } & React.ComponentPropsWithoutRef<T>
: CommonProps & { href?: never } & React.ComponentPropsWithoutRef<'button'>
)
const Button = React.forwardRef(<T extends 'a' | 'button' | never>(props: Props<T>, ref: React.Ref<React.ComponentRef<T>>) => {
if (typeof props.href === 'string') {
return (
<a className="button" ref={ref as React.Ref<React.ComponentRef<'a'>>}>
{props.children}
</a>
)
}
return (
<button className="button" ref={ref as React.Ref<React.ComponentRef<'button'>>}>
{props.children}
</button>
)
})
export default Button
Текущий результат:
На данный момент я чувствую что иду в нужном направлении, но все никак не могу понять что конкретно делаю не так, уже мозг вскипает, если честно. Повторюсь что конкретно я ожидаю:
- Вызов
<Button />должен ожидать атрибуты только для кнопки (ButtonProps); - Вызов
<Button href="/" />должен ожидать атрибуты только для ссылки (AnchorProps); - Вызов
<Button ref={buttonRef} />должен ожидать атрибуты только для кнопки (ButtonProps); - Вызов
<Button ref={anchorRef} />должен ожидать атрибуты только для ссылки (AnchorProps).
Надеюсь понятно объяснил, заранее благодарю)