storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.56k stars 9.3k forks source link

[Bug]: Typescript complains of default arg value when using mapped values #23269

Open Goncalongt opened 1 year ago

Goncalongt commented 1 year ago

Describe the bug

I am trying to create a story, and according to the docs, JSX Elements aren't JSON Serializable so I can't pass them directly as options to my controls. Due to that, I'm using the mapping feature to map the radio control string options to StyledComponents.

However, despite the code actually seeming to work, typescript complains that 'string' is not assignable to ReactElement while defining the default value in the args property:

import type { Meta } from '@storybook/react';
import { StoryObj } from '@storybook/react';
import { styled } from '@mui/material';
import OverflowTooltip from './overflow-tooltip';

const Child = styled('div')({
    maxWidth: '10em',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    whiteSpace: 'nowrap',
});

const shortText = 'Short text';
const longText = 'This is a long text that overflows';

const meta: Meta<typeof OverflowTooltip> = {
    component: OverflowTooltip,
    title: 'Packages/Core/Overflow Tooltip',
    args: {
        title: longText,
        children: 'Short', // <--- Typescript complains about this
    },
    argTypes: {
        // ...
        children: {
            name: 'Child Text',
            control: 'radio',
            options: ['Short', 'Long'],
            mapping: {
                Short: <Child>{shortText}</Child>,
                Long: <Child>{longText}</Child>,
            },
            description:
                'If a long text is selected the content will overflow and the tooltip should show up.',
        },
    },
};

I believe that this is a bug, but I can also be doing something wrong, any feedback?

To Reproduce

No response

System

System:
    OS: Windows 10 10.0.20348
    CPU: (8) x64 Intel(R) Xeon(R) Gold 6258R CPU @ 2.70GHz
Binaries:
    Node: 18.15.0 - C:\Program Files\nodejs\node.EXE
    npm: 9.5.0 - C:\Program Files\nodejs\npm.CMD
Browsers: {}
npmPackages:
    @storybook/addon-essentials: ^7.0.7 => 7.0.20 
    @storybook/core-common: ^7.0.7 => 7.0.20 
    @storybook/core-server: ^7.0.7 => 7.0.20 
    @storybook/react-vite: ^7.0.7 => 7.0.20

Additional context

I have tried omitting that line, but I get the following error: Error shown while omitting the line

I have also tried assigning the value directly to the children arg/prop:

children: <Child>{shortText}</Child>

but I get the following warning in the console: Warning shown when directly assigning the non serializable value

oleksandr-danylchenko commented 7 months ago

I'm having the same exact issue with Storybook 8.0.4! The children type in the args doesn't match the options keys, but it still requires me to pass the ReactElement...

Although the "Dealing with complex values" documentation using the mapper for the JSX values is recommended and examples show just that 🤷🏻‍♂️


For now, I just silenced it with @ts-expect-error:

const meta = {
    title: '...',
    component: ...,
    tags: ['autodocs'],
    argTypes: {
        children: {
            options: Object.keys(annotatorContent),
            mapping: annotatorContent
        }
    }
} satisfies Meta<typeof WebtextsAnnotator>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Plaintext: Story = {
    args: {
        // @ts-expect-error: The enum is mapped to the page content
        children: 'Plaintext'
    }
};

But it is a flaw in the documentation and/or the StoryObj type inference 🤷🏻‍♂️

oleksandr-danylchenko commented 1 month ago

For now, the workaround I came up with is to use the React.PropsWithChildren, which defines children?: ReactNode | undefined. The ReactNode covers the string type, and it matches your mapped string too