I am building a reusable Card component that can render as an a tag, a button tag, or a custom Next.js Link based on an as prop. I am struggling to get the TypeScript typing correct so that standard attributes (like href for links, type for buttons) are auto-completed and typesafe. Can someone show me a clean way to achieve this?
You should look into Polymorphic Components pattern. Here is a clean boilerplate using TypeScript generics:
type PolymorphicRef<C extends React.ElementType> = React.ComponentPropsWithRef<C>['ref'];
type PolymorphicProps<C extends React.ElementType, Props = {}> = {
as?: C;
} & Props & Omit<React.ComponentPropsWithoutRef<C>, keyof Props>;
This is how I type all my design system cards and buttons!
Wow Jane, this is incredibly clean! The Omit utility is exactly what I was missing. It works perfectly with custom Router links too. Thank you so much!
Use ``` code ``` for syntax highlighting