Context & Code
We extended our button like so:
export type ButtonProps<P = Record<string, unknown>> = P & {
children: ReactNode | string
onClick?: () => void
className?: string
disabled?: boolean
secondary?: boolean
}
const Button = <P extends Record<string, unknown>>({
children,
onClick,
className,
disabled = false,
secondary = false,
}: ButtonProps<P>) => {
...
}
This overloading means we can implement new buttons with additional props, without messing with the original button, à la:
const FooterTwoButtons = ({
secondaryOnClick,
secondaryIconType,
icon,
className,
...props
}: ButtonProps<TwoButtonsProps>) => {
return (
<div className={clsx('grid grid-cols-5', className)}>
<Button onClick={secondaryOnClick} secondary>
{(secondaryIconType !== undefined && (
<Icon type={secondaryIconType} />
)) ||
(icon !== undefined && icon)}
</Button>
<FooterButton {...props}>{props.children}</FooterButton>
</div>
)
}
It's super nice as it allows more ephemeral button components to be extended from our base type. Everything compiles and works as expected, except for storybook...
Problem
I cannot seem to find any questions/issues of a modern storybook component allowing for generic props.
ExtendedButtonProps
story:
export const ButtonExtendedProps: ComponentStory<typeof Button> = ({
secondaryIconType,
children,
...props
}: ButtonProps<ExtendedProps>) => {
return (
<div>
<Button secondaryIconType={secondaryIconType} {...props}>
{children}
</Button>
</div>
)
}
ButtonExtendedProps.args = {
...Default.args,
secondaryIconType: 'CircledX',
}
Here is the tsc compiler error, which appears on ButtonExtendedProps
in the above code:
module ButtonExtendedProps
const ButtonExtendedProps: ComponentStory<(<P extends Record<string, unknown>>({ children, onClick, className, disabled, secondary, }: ButtonProps<P>) => JSX.Element)>
Type '{ ({ secondaryIconType, children, ...props }: ButtonProps<ExtendedProps>): JSX.Element; args: Partial<Record<string, unknown> & { children: ReactNode; onClick?: (() => void) | undefined; className?: string | undefined; disabled?: boolean | undefined; secondary?: boolean | undefined; }> | undefined; }' is not assignable to type 'ComponentStory<(<P extends Record<string, unknown>>({ children, onClick, className, disabled, secondary, }: ButtonProps<P>) => Element)>'.
Type '{ ({ secondaryIconType, children, ...props }: ButtonProps<ExtendedProps>): JSX.Element; args: Partial<Record<string, unknown> & { children: ReactNode; onClick?: (() => void) | undefined; className?: string | undefined; disabled?: boolean | undefined; secondary?: boolean | undefined; }> | undefined; }' is not assignable to type 'ArgsStoryFn<ReactFramework, Record<string, unknown> & { children: ReactNode; onClick?: (() => void) | undefined; className?: string | undefined; disabled?: boolean | undefined; secondary?: boolean | undefined; }>'.
Types of parameters '__0' and 'args' are incompatible.
Type 'Record<string, unknown> & { children: ReactNode; onClick?: (() => void) | undefined; className?: string | undefined; disabled?: boolean | undefined; secondary?: boolean | undefined; }' is not assignable to type 'ButtonProps<ExtendedProps>'.
Property 'secondaryIconType' is missing in type 'Record<string, unknown> & { children: ReactNode; onClick?: (() => void) | undefined; className?: string | undefined; disabled?: boolean | undefined; secondary?: boolean | undefined; }' but required in type 'ExtendedProps'.ts(2322)
Can anyone spot what I've missed here? Is there a page in the storybook docs which provides examples of this? I looked around quite a bit today, but not sure which keywords to search. Any tips are much appreciated. Cheers.
As it would happen, ComponentStory<typeof Button> === Story<ButtonProps>
So the resulting story signature looked like:
export const ButtonExtendedProps: Story<ButtonProps<ExtendedProps>> = ({
altIconType,
altClassName,
altAriaLabel,
children,
clean,
...props
}: ButtonProps<ExtendedProps>) => {