Migrating your React boilerplate project from using Flow to Typescript

Amal Jossy,typescript

This particular set of instructions are for those who wish to migrate their react app created from React-Boilerplate-Flow to use Typescript instead of flow.

I use vscode for my work and there are certain instruction that ask you to do stuff in vscode, just do the same using whatever editor you want. I recommend vscode

  1. Remove '.flowconfig' and 'flow-typed'

    you dont need these anymore as you are getting rid of flow

  2. Remove flow-bin from dependencies

    Go to package.json and remove the dependencie relating to flow. Starting with flow-bin

  3. Add Typescript to dependencies

    I used version 3.8 and the instructions may differ for some versions

  4. Add tsconfig.json (opens in a new tab) to / from react-boilerplate-typescript

    React-Boilerplate already had typescript version. It will be easier if you just copy the file first an then modify. You dont have to start from scratch this way. Make the following changes

    • set compilerOptions.incremental=true
    • "include": ["app/**/*"]
    • "exclude": ["node_modules", "internals/templates/\*\*/*", "app/\*\*/*.test.*"]
  5. Add "@babel/preset-typescript", "@typescript-eslint/eslint-plugin", "@typescript-eslint/parser" to dependencies, update eslint

    Use the package manager to add the required dependencies. Might as well update eslint to work well with the newly added dependencies

  6. Remove "@babel/preset-flow", "babel-preset-flow", "eslint-plugin-flowtype" dependencies

    These were used by flow and are not required anymore

  7. Modify .eslintrc to use @typescript-eslint
    • parser: @typescript-eslint.parser
    • extends: ['airbnb-typescript', 'prettier', 'prettier/react', 'prettier/@typescript-eslint'],
    • plugins: ['prettier', 'redux-saga', 'react', 'react-hooks', 'jsx-a11y', '@typescript-eslint'],
    • parserOptions: { project: './tsconfig.json', },
  8. Update babel config
    • change '@babel/preset-flow', to '@babel/preset-typescript',
  9. Prepare the codemod

    The existence of this codemod is what made us optimistic about the migration. Last I used the codemod It neede some tweaking. The major issue was git detects the file extension change as delete and add, which will cause the project to lose commit history of the affected file. Also the codemod uses prettier on the project but the version of prettier used by the codemod doesnt support optional chaining syntax and throws errors

  10. Run the codemod

    node path\to\flow-to-ts.js --prettier --semi --single-quote --tab-width 2 --bracket-spacing --print-width 80 --write --delete-source app/**/*.js

  11. Search and replace 'Object' to 'any'

    You shouldnt have had these types in your flow-typed project in the first place. If you dont, you can skip this step, otherwise make this change in every concerned file. VS code will help yo with this

  12. Search and replace @flow annotations that survived the codemod

    The codemod fill strip away most @flow annotations but some may still persist becuase the formatting might've been different from what the codemod was looking for

  13. Run prettify
  14. Remove vscode extensions for flow
  15. Update file references

    The codemod will have changed file extensions. Update all file references that point to the old .js or .jsx fieles

    • webpack -- entry: app.tsx -- resolve: .ts and .tsx files as well -- test: /.[j|t]sx?$/ for babel-loader
    • package.json -- lint-staged, use "*.{js,jsx,ts,tsx}" pattern
    • .gitattributes -- add *.ts text eol=lf and *.tsx text eol=lf
  16. Modify .eslint if eslint was updated and you didnt have these configured
     'react/prop-types': 0,
     'react/jsx-props-no-spreading': 0,
     'react/jsx-curly-newline': 0,    
     'react/jsx-curly-newline': 0,
  17. Add missing type definitions

    Create app/types/assets.d.ts (https://webpack.js.org/guides/typescript/#importing-other-assets (opens in a new tab)) and add the following lines

    declare module '*.svg' {
    	const content: any;
    	export default content;
    }
    declare module '*.png' {
    	const content: any;
    	export default content;
    }
  18. Update prettier to >1.19 to work with ts
  19. Update jest and jest.config
  20. utility-types

    $Values and other flow utility types are not available in ts, codemod suggests utility-types package, search for files with 'utility-types' imports and manually implement the same functionality using ts -- $Values can be replaced by using enum in ts

  21. update storybook to work with typescript

    If your project uses storybook do these steps as well

    • update version to ^5.3
    • search and replace incorrect file extensions
    • add custom webpack config
      module.exports = {
      	stories: ['../app/**/*.stories.tsx'],
      	webpackFinal: async config => {
      	  config.module.rules.push({
      		test: /\.(ts|tsx)$/,
      		loader: require.resolve('babel-loader'),
      		options: {
      		  presets: ['@babel/preset-react','@babel/preset-typescript'],
      		},
      	  });
      	  config.resolve.extensions.push('.ts', '.tsx');
      	  return config;
      	},
      	};