I have a base button component which only accepts a limited number of props, and then multiple variations of that which pass through those props.
For example Button
is a wrapper for BaseButton
that sets type=button
. SubmitButton
is a wrapper that sets a type=submit
.
The problem is that I don't know how to best document that Button
accepts the same parameters as BaseButton
except type
. If I manually document them as @param
entries I get a linting error that this component doesn't accept arguments by those names.
I need to "extend" the tsdoc for the BaseButton
. Maybe I just use @see
? I was hoping to allow those arguments to show up in VSCode hints.
This is further complicated by the fact that I'm re-using existing react types rather than declaring them myself on an interface. But I won't worry about that issue for this post.
// Borrow button element props from react
type BaseButtonProps = Pick<ButtonHTMLAttributes<HTMLButtonElement>, 'disabled' | 'onClick' | 'type'>;
// Define a basic interface for all button types
export interface ButtonProps extends Accented, BaseButtonProps {}
/**
* Creates a button component without any defaults.
*
* @param accent The UI accent
* @returns A basic button component
*/
const BaseButton = ({ accent, children, ...props }: PropsWithChildren<ButtonProps>): JSX.Element =>
<button className={clsx('btn', styles.button, accent && styles[accent])} {...props}>{children}</button>
// Create a pre-typed button props definition
type TypedButtonProps = PropsWithChildren<Omit<ButtonProps, 'type'>>;
export const SubmitButton = ({ children, ...props }: Omit<TypedButtonProps, 'onClick'>): JSX.Element =>
<BaseButton type='submit' {...props}>{children}</BaseButton>
/**
* Creates a button component of type=button which accepts a click handler.
*
* @param onClick Handle button click events (optional)
* ISSUE IS HERE... How can I document other props like "accent" and "disabled" without duplicating them for every variant
* @returns Button component
*/
export const Button = ({ onClick, children, ...props }: TypedButtonProps): JSX.Element => {
const onButtonClick = useCallback((event: MouseEvent<HTMLButtonElement>): void => {
event.preventDefault()
event.stopPropagation()
onClick?.(event)
}, [onClick])
return <BaseButton onClick={onButtonClick} type='button' {...props}>{children}</BaseButton>
}