'Overload React component
Considering we have a React component that depending on different props can render either <button> or <a> or React Router <Link>
Not sure if it is even possible in this case but how can we overload this component to accept the correct props for each case?
const Button: FC<ButtonProps> = forwardRef(
(
{
className,
disabled,
onClick,
children,
href,
to,
downloadable,
...rest
},
ref
) => { ... }
In addition to some shared props, unique props combination in each case is
interface BaseProps {
bSize?: ButtonSize;
bType?: ButtonType;
bLayout?: ButtonLayout;
}
interface ButtonBaseProps extends ButtonHTMLAttributes<HTMLButtonElement> {
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
ref?: Ref<HTMLButtonElement>;
}
interface ExternalLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
ref?: Ref<HTMLAnchorElement>;
href?: string;
downloadable?: boolean;
}
interface ReactRouterLinkProps
extends ForwardRefExoticComponent<LinkProps & RefAttributes<HTMLAnchorElement>> {
onClick?: (event: MouseEvent<HTMLAnchorElement>) => void;
ref?: Ref<HTMLAnchorElement>;
to?: string;
}
export type ButtonProps = BaseProps & (ButtonBaseProps | ExternalLinkProps | ReactRouterLinkProps);
Normally for a function, I would do something like this
function foo(bar: string[]): string[];
function foo(bar: number[]): number[];
function foo(bar: string[] | number[]): string[] | number[] { ... }
Solution 1:[1]
What you did is correct, you need just one thing, you need to add an additional prop type to help TypeScript to know which type you are using in your code:
import * as React from 'react';
import {LinkProps} from 'react-router-dom';
import './style.css';
export default function App() {
return (
<CustomComponent type='anchor' bSize='big' />
);
}
interface CommonProps {
bSize?: any;
bType?: any;
bLayout?: any;
}
interface ButtonProps extends React.HTMLProps<HTMLButtonElement> {
type: 'button'
}
interface AnchorProps extends React.HTMLProps<HTMLAnchorElement> {
type: 'anchor'
}
interface CustomLinkProps extends LinkProps {
type: 'link'
}
type Props = (ButtonProps | AnchorProps | CustomLinkProps) & CommonProps
function CustomComponent (props: Props) {
return <div></div>
}
And don't forget to use Discriminating Unions, check this: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html
Demo: https://stackblitz.com/edit/react-ts-3yfbmt?file=App.tsx
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
