Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storybook in Create React App withTypeScript still compiles when component has illegal types

Im trying to add Storybook to Create React App and have everything in TypeScript. I've got it compiling however when I have illegal types in a React component then Create React App errors (as it should) but Storybook still compiles.

package.json file:

{
  "name": "hiit5",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@emotion/core": "^10.0.15",
    "@types/jest": "^24.0.17",
    "@types/node": "^12.7.2",
    "@types/react": "^16.9.1",
    "@types/react-dom": "^16.8.5",
    "prop-types": "^15.7.2",
    "react": "^16.9.0",
    "react-docgen-typescript-webpack-plugin": "^1.1.0",
    "react-dom": "^16.9.0",
    "react-scripts": "3.1.0",
    "typescript": "^3.5.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@storybook/addon-actions": "^5.1.11",
    "@storybook/addon-info": "^5.1.11",
    "@storybook/addon-knobs": "^5.1.11",
    "@storybook/addon-links": "^5.1.11",
    "@storybook/addons": "^5.1.11",
    "@storybook/react": "^5.1.11",
    "@types/storybook__react": "^4.0.2",
    "awesome-typescript-loader": "^5.2.1",
    "babel-core": "^6.26.3",
    "babel-loader": "^8.0.6",
    "prettier": "^1.18.2",
    "react-docgen-typescript-loader": "^3.1.1",
    "storybook-addon-jsx": "^7.1.5"
  }
}

Root tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react"
  },
  "include": [
    "src"
  ]
}

.storybook/config.ts

import { configure } from "@storybook/react";

// automatically import all files ending in *.stories.js
const req = require.context("../stories", true, /\.stories\.tsx$/);
function loadStories() {
  req.keys().forEach(filename => req(filename));
}

configure(loadStories, module);

.storybook/tsconfig.ts

{
  "compilerOptions": {
    "outDir": "build/lib",
    "module": "commonjs",
    "target": "es5",
    "lib": ["es5", "es6", "es7", "es2017", "dom"],
    "sourceMap": true,
    "allowJs": false,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDirs": ["src", "stories"],
    "baseUrl": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build", "scripts"]
}

.storybook/webpack.config.js

module.exports = ({ config, mode }) => {
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    loader: require.resolve("babel-loader"),
    options: {
      presets: [["react-app", { flow: false, typescript: true }]]
    }
  });
  config.resolve.extensions.push(".ts", ".tsx");
  return config;
};
like image 834
Evanss Avatar asked Aug 16 '19 14:08

Evanss


1 Answers

The reason Storybook still compiles despite type errors is that Babel preset "react-app" from Create React App (CRA) only strips off the TypeScript definitions and emits all files without further compiler checks.

react-app / babel-preset-react-app can carry the CRA Babel configuration over to other builds, like Storybook. Internally, it is based on @babel/preset-typescript, which handles .ts/tsx files like this:

While Babel can take over compiling/transpiling – doing things like erasing your types and rewriting the newest ECMAScript features to work in older runtimes – it doesn’t have type-checking built in, and still requires using TypeScript to accomplish that. So even if Babel builds successfully, you might need to check in with TypeScript to catch type errors. Link

Solution

1.) babel-preset-react-app

Stick with babel-preset-react-app and use tsc to check for compile errors. The Microsoft/TypeScript-Babel-Starter repository shows how to configure npm scripts that run a type check with tsc:

"type-check": "tsc --noEmit",
"type-check:watch": "npm run type-check -- --watch",

Those scripts could be further wrapped by some IDE task (e.g. if you use VS Code).

2.) Full-fledged compiler, e.g. awesome-typescript-loader

Use some Webpack TypeScript loader like awesome-typescript-loader that makes use of the full compiler during bundling (Link).

webpack.config.js:

module.exports = ({ config, mode }) => {
  config.module.rules.push({
    test: /\.(ts|tsx)$/,
    loader: "awesome-typescript-loader"
  });
  config.resolve.extensions.push(".ts", ".tsx");
  return config;
};

Settings

tsconfig.json:

{
  ...
  "compilerOptions": {
    // if you use awesome-typescript-loader
    "jsx": "react"
  },
  // include stories and src for type checking
  "include": ["src", "stories"]
}
like image 142
ford04 Avatar answered Oct 31 '22 22:10

ford04