如何将JS项目迁移到TS项目?

学习了 TypeScript ,肯定是跃跃一试、小试牛刀,想找个已有 JavaScript 项目改造一下。

首先做一下心理按摩:对已有项目进行迁移将是一个渐进过程,不会一气呵成。

项目的迁移有三个主流策略

  • 共存策略
  • 宽松策略
  • 严格策略

我们以一个 react 项目做例子,三个策略的前两步是一样的:

安装

安装 typescript 和 react 声明文件

$ npm i typescript @types/react @types/react-dom
复制代码

初始化 tsconfig.json

$ tsc --init
复制代码
  • tsconfig.json
    {
      "jsx": "react"
    }
    复制代码

共存策略

所谓共存策略:原来的 JS 代码不做修改,新增的代码用 TS 编写。

babel-loader? ts-loader?

如果你的构建工具深度依赖 babel,则可以选择使用 babel-loader 做语言转换、tsc 做类型检查;否则可以选择更轻量的 ts-loader

鉴于目前大多数的 React 项目都使用了 babel,我们先看选择 babel 的处理方式

babel-loader

  • 安装 @babel/preset-typescript

    $ npm i -D @babel/preset-typescript
    复制代码
  • 修改 babel 配置

    {
      "presets": [
        "@babel/env",
        "@babel/preset-react",
    +    "@babel/preset-typescript"
      ],
      "plugins": [
        "@babel/proposal-class-properties",
        "@babel/proposal-object-rest-spread"
      ]
    }
    复制代码
  • 修改 webpack.base.config.js

    module.exports = {
      // ...
      resolve: {
        extensions: [".js", ".jsx", ".ts", ".tsx"],
      },
      module: {
        rules: [
          {
            test: /\.(j|t)sx?$/,
            use: [
              {
                loader: "babel-loader",
              },
            ],
            exclude: /node_modules/,
          },
        ],
      },
    };
    复制代码
    • 添加类型检查

      • tsconfig.json

        {
          "compilerOptions": {
            "noEmit": true
          }
        }
        复制代码
      • package.json:添加类型检查脚本

        {
          // ...
          "scripts": {
            // ...
            "type-check": "tsc --watch"
          }
        }
        复制代码

ts-loader

ts-loader 的处理方式会更简单

  • 安装 ts-loader

    npm i ts-loader -D
    复制代码
  • 修改 webpack.base.config.js

    module.exports = {
      // ...
      resolve: {
        extensions: [".js", ".jsx", ".ts", ".tsx"],
      },
      module: {
        rules: [
          // ...
          {
            test: /\.tsx?$/,
            use: [
              {
                loader: "ts-loader",
              },
            ],
            exclude: /node_modules/,
          },
        ],
      },
    };
    复制代码

js、jsx 也不能放过

  • tsconfig.json

    ** 所有子目录。包括子目录的子目录。 * 只是一级子目录

    {
      "include": ["./src/**/*"],
      "compilerOptions": {
        // ...
        "allowJs": true,
        "checkJs": true
      }
    }
    复制代码

类型检查的报错,并不影响构建。

在不修改 JS 代码的前提下,有两种处理报错的方式:

  • @ts-nocheck

    // @ts-nocheck
    export function add(x, y) {
      return x + y;
    }
    复制代码
  • JSDoc

    这种方法在写代码时,也会进行类型检查

    /**
     * @param {number} x
     * @param {number} y
     */
    export function add(x, y) {
      return x + y;
    }
    复制代码

宽松策略

所谓宽松策略:将所有的 js/jsx,重命名为 ts/tsx。并且在不修改代码的基础上,使用最宽松的检查规则,忽略剩余的报错,使工程跑起来。

重命名

我们借助 shelljs 来完成重命名工作,先安装一下 shelljs

node 命令默认寻找 js 文件,所以我们还需要安装 ts-node 来帮我们查找 ts 文件。

$ npm i -D shelljs @types/shelljs ts-node
复制代码

在根目录新建 renameJS.ts

import * as shelljs from "shelljs";

shelljs
  .find("src") // 查找src文件夹,并返回一个数组
  .filter((file) => file.match(/\.jsx?$/)) // 过滤出 js/jsx 文件
  .forEach((file) => {
    let newName = file.replace(/\.j(sx?)$/, ".t$1");
    shelljs.mv(file, newName); // 重命名
  });
复制代码

shellmv 命令为移动(moving)的意思,其实是用 cprm 来完成的。

配置重命名脚本(package.json):

{
  "scripts": {
    // ...
    "rename-js": "ts-node renameJS.ts"
  }
}
复制代码

webpackpackage 的两处入口文件修改:jsx -> tsx

修改类型检查规则

  • tsconfig.json

    {
      "compilerOptions": {
        // "allowJs": true,
        // "checkJs": true,
        "strict": false
        /* Additional Checks */
        // ... 全都关闭(false)
      }
    }
    复制代码

这样宽松的检查规则,会减少大部分的报错;但新增的 ts 文件也失去了严格的类型检查。

所以,这更适合当过渡策略。

严格策略

所谓严格策略,即开启最严格的类型检查规则,处理所有的报错。

首先也需要对文件重命名,见【宽松策略/重命名】。

类型检查规则(tsconfig.json),类型检查相关配置都打开(true):

{
  "compilerOptions": {
    /* Strict Type-Checking Options */
    "strict": true
    // ...

    /* Additional Checks */
    // ...
  }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享