Search code examples
typescriptstorybookrollupjs

TypeScript parameter properties not working with Storybook + Rollup (in development environment)


TypeScript comes with a useful feature called parameter properties for turning a constructor parameter into a class property with the same name and value. However, for some reason, when using TypeScript with Storybook and Rollup, constructor properties are not transpiled to class properties.

Example code:

my_class.ts

class Params {
  constructor(
    public property: number
  ) {}
}

In a development Storybook environment (spun up with yarn storybook), Params.property is undefined and cannot be accessed.

Here are my configuration files:

rollup.config.js

import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';

const packageJson = require('./package.json');

export default {
    input: 'src/index.ts',
    output: [
        {
            file: packageJson.main,
            format: 'cjs',
            sourcemap: true,
        },
        {
            file: packageJson.module,
            format: 'esm',
            sourcemap: true,
        },
    ],
    plugins: [
        peerDepsExternal(),
        resolve(),
        commonjs(),
        typescript({
            tsconfig: './tsconfig.json',
        }),
    ],
};

package.json

{
    "name": "cursor-ui",
    "version": "0.1.0",
    "license": "MIT",
    "devDependencies": {
        "@babel/core": "^7.16.0",
        "@rollup/plugin-commonjs": "^21.0.1",
        "@rollup/plugin-node-resolve": "^13.0.6",
        "@rollup/plugin-typescript": "^8.3.0",
        "@storybook/addon-actions": "^6.4.9",
        "@storybook/addon-essentials": "^6.4.9",
        "@storybook/addon-links": "^6.4.9",
        "@storybook/react": "^6.4.9",
        "@types/react": "^17.0.35",
        "babel-loader": "^8.2.3",
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "rollup": "^2.60.0",
        "rollup-plugin-peer-deps-external": "^2.2.4",
        "rollup-plugin-typescript2": "^0.31.0",
        "styled-components": "^5.3.3",
        "themeprovider-storybook": "^1.8.0",
        "typescript": "^4.5.2"
    },
    "peerDependencies": {
        "react": "^16.8.0",
        "react-dom": "^16.8.0",
        "styled-components": ">= 5"
    },
    "dependencies": {},
    "scripts": {
        "storybook": "start-storybook -p 6006",
        "build-storybook": "build-storybook",
        "build": "rollup -c"
    },
    "main": "lib/index.js",
    "module": "lib/index.esm.js",
    "types": "lib/index.d.ts",
    "files": [
        "src",
        "lib"
    ]
}

tsconfig.js

{
    "compilerOptions": {
        "target": "es5",
        "rootDir": "./src",
        "outDir": "./lib",
        "lib": ["dom", "dom.iterable", "esnext"],
        "declaration": true,
        "declarationDir": "./",
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "downlevelIteration": true
    },
    "include": ["src"],
    "exclude": ["node_modules", "lib"]
}

.storybook/main.js

module.exports = {
    stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
    addons: ['@storybook/addon-links', '@storybook/addon-essentials', 'themeprovider-storybook/register'],
};

As far as I'm aware, Storybook uses webpack under the hood. Is there some configuration that needs changing? Or is the problem caused by something else?

Note: After compiling the library (using yarn build) the output appears to be correct with the class properties present. The problem only occurs during development.


Solution

  • This issue is caused by a known bug in Storybook. As a workaround, add the following code snippet to .storybook/main.js:

    babel: async options => {
            return {
                ...options,
                plugins: options.plugins.filter(x => !(typeof x === 'string' && x.includes('plugin-transform-classes'))),
            };
        },
    

    Please refer to the linked GitHub issue for more details and explanations.