Is your feature request related to a problem? Please describe
It's a bit painful setting up globals in preview.js, having to refer back to docs and risk errors without strict types.
Describe the solution you'd like
I tried writing a preview.d.ts that enforces the structure from Storybook docs, but my preview.js didn't seem to enforce it or provide intellisense. I don't have much experience writing definition files, but it should work something like:
import { IconKey } from '@storybook/components/dist/icon/icons'
export declare type GlobalType<T> = {
name: string
description?: string
defaultValue?: T
toolbar: {
icon?: IconKey
items: Array<{
title: string
value: T
left?: string
right?: string
icon?: IconKey
}>
}
}
export declare type GlobalTypes = Record<string, GlobalType<unknown>>
export declare const globalTypes: GlobalTypes
Describe alternatives you've considered
Alternatively, Storybook could allow preview.js to be provided as preview.ts and expose GlobalTypes with other types like Meta and Story. That would allow using the utility type above to enforce strictly typed values in items array. e.g.
// .storybook/preview.ts
import { GlobalType } from '@storybook/react/types-6-0'
type CountryCodes = 'en' | 'fr' | 'es' | 'zh' | 'kr'
export const globalTypes: {
locale: GlobalType<CountryCodes>
} = {
locale: {
name: 'Locale',
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'fr', right: '🇫🇷', title: 'Français' },
{ value: 'es', right: '🇪🇸', title: 'Español' },
{ value: 'zh', right: '🇨🇳', title: '䏿–‡' },
{ value: 'kr', right: '🇰🇷', title: '한êµì–´' },
],
},
},
}
Are you able to assist to bring the feature to reality?
Yep, can do with a little help understanding your conventions.
@timkinnane thanks for raising the problem and sketching out a solution!
here's how I originally conceived this--it probably needs some refinement:
In this ArgTypes data structure, name, type, defaultValue, and description are standard fields in all ArgTypes (analogous to PropTypes in React). The table and control fields are addon-specific annotations.
So given that, the type for globalTypes would be:
import { ToolbarAnnotation } from '@storybook/addon-toolbars';
export const GlobalTypes = ArgTypes<ArgType & ToolbarAnnotation> = { ... }
What's needed to make this happen:
interface ArgTypes<T = ArgType> { ... }interface ToolbarAnnotation { toolbar?: ToolbarConfig }What do you think?
@tooppaaa thanks for discussion! @yannbf this reminds me of your proposal for typed parameters
Maybe we can tackle this with module augmentation indeed, here's a quick sketch:
// ./storybook/typings.d.ts
import { ToolbarAnnotation } from '@storybook/addon-toolbars';
declare module '@storybook/core/types' {
export interface ArgTypes extends ToolbarAnnotation { ... }
}
The types that we augment would need to be exported as interfaces if I'm not mistaken
Thanks so much. So lovely to see such enthusiastic and considered feedback.
@shilman and @yannbf - both solutions look fine to me as far as exporting a type.
@shilman Making ArgType a generic would be great because you could strict type your optional and default values, as I've done with Country Codes in the locale example, where trying to add a value that doesn't exist in the union type of possible countries would give a type error.
However that would still require parsing a Typescript preview file? Is that a possibility? I'd love Storybook to look for preview as a glob, like preview.@(js|jsx|ts|tsx) - That would allow both global types and global decorators to be typed and follow the same patterns as my project's stories.
@yannbf Would your proposal add ToolbarAnnotation attributes to all ArgTypes?
How would the augmented type be consumed in preview.js? I've never seen module augmentation and it looks like magic.
I'll have to experiment.
@timkinnane I'm pretty sure preview.ts is already supported. Have you run into any problems trying it?
@timkinnane I'm pretty sure
preview.tsis already supported. Have you run into any problems trying it?
Oh snap - it does. I had tried it but something else must have been an issue, because it works now. Thanks now I can experiment with the type suggestions.
FYI I haven't forgotten about this. I've got a working example and was rather simple to use existing types.
Haven't had time to rebase and tidy up for a PR, but I thought I just at least publish where I'm up to.
Fork
https://github.com/timkinnane/storybook/tree/12658-typed-globalTypes
Most helpful comment
Maybe we can tackle this with module augmentation indeed, here's a quick sketch:
The types that we augment would need to be exported as interfaces if I'm not mistaken