Describe the bug
Suppose I'm using Storybook 6 with @storybook/addon-controls
with React and TypeScript.
Per the medium article, basic usage of control values like so:
export const Basic = (args) => <Button {...args} />;
Basic.args = { label: 'hello button' };
Suppose the Button has these props:
interface ButtonProps {
label?: string;
}
If I ever mutate the interface, there is no type interference for <storyName>.args
.
There's value in having the component's types percolate through the system and apply to args: (1) Validating my stories conform to the component's interface, and (2) if I mutate the interface, I can easily update my stories accordingly.
In TypeScript, if I want typings, for every story in my project I must write:
interface Story {
(): any;
args?: ButtonProps; // Optional since args is defined after function declaration
}
export const Basic: Story = (args) => <Button {...args} />;
Basic.args = { label: 'hello button' };
To Reproduce
See above code samples.
Expected behavior
It seems verbose and overly ceremonious to have to define a new type for my stories. Is there a better way? Maybe storybook could ship an interface, so I could do something like this:
import { Story } from '@storybook/...';
export const Basic: Story<ButtonProps> = (args) => <Button {...args} />;
Basic.args = { label: 'hello button' };
where Story is
interface Story<T> {
(): any;
args?: T;
}
We introduced typescript types in 6.0: https://github.com/storybookjs/storybook/blob/next/docs/snippets/react/page-story.ts.mdx
We plan to enhance them in 6.1, but hopefully these address your basic needs. LMK if they don't!
Here are the types I'm currently using, better argTypes
, hope it helps
https://gist.github.com/rabelloo/bae0397d6a331d939eacdb3e8849220f
It appears using Template.bind({})
results in type any
. To have each story's args typechecked, you must manually specify the type.
@petermikitsh .bind({})
should return the type of the function you're binding. See TypeScript playground example.
I think the reason you're seeing this is because you haven't enabled strictBindCallApply
in your TS config.
@torkelrogstad I'm running into the same problem as @petermikitsh and I've got strictBindCallApply: true
in my tsconfig.json
I'd suggest to create a minimal reproduction in the TypeScript playground.
Any way to fix this?
Failed to compile.
/Users/joaopaulofricks/www/xxx-Design-System/src/stories/components/Button.stories.tsx
TypeScript error in /Users/joaopaulofricks/www/xxx-Design-System/src/stories/components/Button.stories.tsx(8,20):
Parameter 'args' implicitly has an 'any' type. TS7006
6 | storiesOf('Atoms/Button', module)
7 | .addDecorator(withKnobs)
> 8 | .add('Default', (args) => <Button {...args}>Default</Button>, {
| ^
9 | component: Button,
10 | })
11 | .add(
Workaround:
8 | .add('Default', (args: any) =>
Or:
8 | .add('Default', (args: ButtonProps) =>
@shilman I have problems with any
in my application. The better approach is to pass the props to the element... I'll try out, thank you :)
@jpcmf I've made a helper function in my project so that it's fully typed whilst having minimal boilerplate for each component.
helpers.tsx:
import * as React from 'react';
import { Story } from '@storybook/react';
import { StoryFnReactReturnType } from '@storybook/react/dist/client/preview/types';
export const templateForComponent = <P,>(Component: (props: P) => StoryFnReactReturnType) => (
props: P
): Story<P> => {
const template: Story<P> = (args) => {
return <Component {...args} />;
};
const story = template.bind({});
story.args = props;
return story;
};
Input.stories.tsx:
import { Meta } from '@storybook/react';
import { templateForComponent } from '../helpers';
import Input from '../../ui-web-library/Form/Input';
const template = templateForComponent(Input);
const meta: Meta = {
title: 'Form/Input',
component: Input,
};
export default meta;
export const Currency = template({
type: 'currency',
fieldName: 'income',
});
It also slims down the code in comparison to using .bind() and .args for each story. Hope that helps!
Most helpful comment
We introduced typescript types in 6.0: https://github.com/storybookjs/storybook/blob/next/docs/snippets/react/page-story.ts.mdx
We plan to enhance them in 6.1, but hopefully these address your basic needs. LMK if they don't!