Skip to content

Instantly share code, notes, and snippets.

@itsjavi
Last active January 27, 2023 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save itsjavi/ec5009b109f2722e6d20683e0a4dde0e to your computer and use it in GitHub Desktop.
Save itsjavi/ec5009b109f2722e6d20683e0a4dde0e to your computer and use it in GitHub Desktop.
TypeScript Polymorphic React Button Component using the "as" property
import React from 'react'
type PolymorphicPropsFactory<T, P> = {
as?: T | React.ElementType
children?: React.ReactNode | undefined
} & React.RefAttributes<T> &
P
type PolymorphicProps<T, FallbackPropsType> =
// as = Function Component
T extends React.FunctionComponent<infer P>
? PolymorphicPropsFactory<T, P>
: // as = Class Component
T extends React.ComponentClass<infer P>
? PolymorphicPropsFactory<T, P>
: // as = HTML Tag
T extends string
? PolymorphicPropsFactory<T, React.HTMLAttributes<T>>
: // ... fallback
PolymorphicPropsFactory<T, FallbackPropsType>
type BtnProps<T> = PolymorphicProps<T, React.ButtonHTMLAttributes<HTMLButtonElement>>
function Btn<T>({ as, ...rest }: BtnProps<T>) {
const BtnTag = as || 'button'
return <BtnTag {...rest} />
}
type LinkProps = {
href: string
children?: React.ReactElement | any
}
const Link = ({ children, href, ...props }: LinkProps) => {
href = href as string
const isInternal = href.startsWith('/') || href.startsWith('#')
if (isInternal) {
return (
<a href={href} {...props}>
{children}
</a>
)
}
return (
<a href={href} {...props} target={'_blank'} rel={'noreferrer'}>
{children}
</a>
)
}
// playing around:
// TSC should complain about the "activeClass" property
const myBtns = (
<>
<Btn as={Link} href="/login" activeClass={''}>
Btn rendered as the "Link" function component
</Btn>
<Btn as={'div'} onClick={() => false}>
Btn rendered as a "div"
</Btn>
<Btn onClick={() => false} type={'button'}>
Default Btn (HTML button element)
</Btn>
</>
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment