I tried to create a react button component that will render or tag based on whether 'href' attribute is presented. On top of that if 'href' is found, 'hrefLang' will be a required attribute.
I tried to accomplish this via conditional type, below is the code:
import { ComponentProps } from "react";
// Conditional Type
type AnchorProps = ComponentProps<"a"> & Required<{ hrefLang: string }>;
type ButtonProps = ComponentProps<"button">;
type HybridProps = AnchorProps | ButtonProps;
type HasHref = Pick<AnchorProps, "href">;
const Hybrid = <T extends HybridProps>(props: T extends HasHref ? AnchorProps : ButtonProps) => {
if ("href" in props) {
const {href, hrefLang, children, ...rest} = props as AnchorProps
return <a href={href} hrefLang={hrefLang} {...rest}>{children}</a>;
}
const {children, ...rest} = props as ButtonProps
return <button {...rest}>{children}</button>;
};
When I tried to use the component
const App = () => {
return (
<>
// Expecting a warning from typescript but it's not
<Hybrid href="/asd">Button 1</Hybrid>
// Working as Expected:
// typescript will complain about missing hrefLang
<Hybrid href="/asd">
// Correct behavior with no warning
<Hybrid>Button 2</Hybrid>
</>
);
};
export default App
I was expecting typescript to warn me of the missing hrefLang attribute in Button 1. But it's not. I was able to achieve the same thing using function overloading, but will like to know why it's not working with conditional type.