Storybook: [Typescript] Fields in arguments do not get compiled as fields.

Created on 14 Aug 2020  路  5Comments  路  Source: storybookjs/storybook

I am using @storybook/[email protected]

Describe the bug
Typescript's fields in constructor feature doesn't get properly compiled, so code like this

  constructor(
    private _service: IAuthService,
    private _storage: IStorageManager,
    public readonly withSecondFactor: boolean
  ) { }

compiled as just

function (_service, _storage, withSecondFactor) {...etc, but nothing to set field values}

Although, if you override the config in main.js like so, it will work properly.

   config.module.rules[0].use[0].options.plugins = [
      '@babel/plugin-proposal-nullish-coalescing-operator',
      '@babel/plugin-proposal-optional-chaining',
      [
        '@babel/plugin-proposal-decorators/lib/index.js',
        { legacy: true },
      ],
    ];

I believe the problem is in plugins, particularly these two:

@babel/plugin-proposal-class-properties/lib/index.js
@babel/plugin-transform-classes

not sure which one of them actually causing a problem though

babel / webpack bug typescript

Most helpful comment

I'm experiencing the same issue with Storybook 6.0.22, and @val-o 's workaround didn't help. managed to make it work with

 config.module.rules[0].use[0].options.plugins = [
      "@babel/proposal-class-properties",
    ];

All 5 comments

cc @gaetanmaisse @mrmckeb @tooppaaa

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

I'm experiencing the same issue with Storybook 6.0.22, and @val-o 's workaround didn't help. managed to make it work with

 config.module.rules[0].use[0].options.plugins = [
      "@babel/proposal-class-properties",
    ];

I have the same issue with Storybook v6.0.26 on a fresh Next.js install.
However, there is no bug on a fresh create-react-app install.

Story used to reproduce the issue

TsIssue.stories.tsx:

import React from 'react';

class MyClass {
  constructor(public readonly myProp: string) {}
}
const myInstance = new MyClass("test")

export default {
  title: 'TS Issue',
};

export const Test = () => <div>{myInstance.myProp}</div>;

The story should print "test". However, it prints nothing when the issue occurs because myInstance.myProp is undefined.

Steps to reproduce on a fresh Next.js install

yarn create next-app
cd my-app
touch tsconfig.json # to tell Next.js to set up the project with Typescript
yarn add --dev typescript @types/react @types/node
yarn run dev # Ctrl+c
npx sb init
# copy TsIssue.stories.tsx to stories/
yarn storybook

--> myInstance.myProp is undefined.

Steps to reproduce on a fresh CRA install

yarn create react-app my-app --template typescript
cd my-app
npx sb init
# copy TsIssue.stories.tsx to stories/
yarn storybook

--> it works.

The only difference between the two examples is the presence of the @storybook/preset-create-react-app addon for CRA, which seems to fix the issue.
I was not able to investigate more.

PS: Storybook v6.1.0-alphaX also has the issue
PS2: I could not test on Storybook v6.0.27. At the time I am writing, this version crashes totally (blank page)

@DPros worked for me. Turns out removing the @babel/plugin-transform-classes plugin also works:

.storybook/main.js:

module.exports = {
  //...
  webpackFinal: async (config) => {
    // Storybook bug: https://github.com/storybookjs/storybook/issues/12019#issuecomment-702207045
    const { options } = config.module.rules[0].use[0];
    options.plugins = options.plugins.filter(excludePlugins([
      '@babel/plugin-transform-classes',
    ]));
    return config;
  }
}

function excludePlugins(excludePaths) {
  return plugin => {
    const name = typeof plugin === 'string' ? plugin : plugin[0];
    if (typeof name !== 'string') {
      throw new Error(`Not a string: ${name}`);
    }
    return !excludePaths.some(path => name.includes(path));
  }
}
Was this page helpful?
0 / 5 - 0 ratings