美文网首页
# 从 JavaScript 到 TypeScript,Reac

# 从 JavaScript 到 TypeScript,Reac

作者: 一拾五 | 来源:发表于2019-10-27 19:47 被阅读0次

    相对于 JavaScript,TypeScript 增加了类型系统。通过静态检查,开发者可以更早地发现语法错误,同时类型标注也带来了清晰的文档。这篇文章记录了几个关于 React 项目从 JavaScript 迁移到 TypeScript 笔者处理过的一些问题,这些问题虽然并不复杂,但是如果在迁移的过程中遇到了,也需要花上不少的时间去调查和寻找解决方案。

    首先推荐阅读微软的一篇 React 项目迁移文档

    简单总结一下,整个迁移的过程可以分为下面两类操作:

    1. 配置 TypeScript 编译器。
    2. 将 JavaScript 文件转化为 TypeScript 文件。

    配置编译器

    1. 安装依赖

    依赖可以分为两类,一类是 TypeScript 编译工具,另一类是第三方依赖的类型声明文件(declarations)。

    安装编译工具,TypeScript 的主流 loader 有 ts-loader 和 awesome-typescript-loader.

    npm install --save-dev typescript ts-loader source-map-loader
    

    安装第三方依赖类型文件,下面的例子只包括了 react 和 react-dom,其他依赖声明可以根据自己项目进行安装。

    npm install --save -D @types/react @types/react-dom
    

    如果最终发布的内容是会被其他项目引用的工具,应该把 @types 包括在发布的文件当中,即 npm i @types/xxx,如果发布的内容不会被其他项目引用,那么安装为 devDependencies 即可,可以参考 stackoverflow 上的这篇讨论

    如果项目开发时使用了热更新(HMR),类型检查会报错 module.hot 类型问题,需要安装 @types/webpack-env 来解决这个类型问题。

    2. webpack 配置更新

    • 添加 resolve 的文件后缀:
    resolve: {
      // changed from extensions: [".js", ".jsx"]
      extensions: [".ts", ".tsx", ".js", ".jsx"]
    },
    
    • 使用 ts-loader 处理 js, jsx, ts, tsx 文件:
    module: {
      rules: [
        // changed from { test: /\.jsx?$/, use: { loader: 'babel-loader' } },
        {
          test: /\.(t|j)sx?$/,
          use: {
            loader: ts-loader',
             options: { // options for spped up compilation
               transpileOnly: true
             }
           }
        },
        // addition - add source-map support
        { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
      ]
    },
    

    项目冷启动开发时(npm start),如果顺序进行类型检查和编译,会花费不少的时间。我们可以另开一个线程来进行类型检查,从而节约时间。fork-ts-checker-webpack-plugin 就是这样一个 webpack plugin,非常推荐使用。

    3. 添加 ts 编译器配置

    // tsconfig.js
    {
        "compilerOptions": {
            "outDir": "./dist/",
            "sourceMap": true,
            "noImplicitAny": true,
            "strictNullChecks": true,
            "module": "es6",
            "target": "es5",
            "jsx": "react",
            "allowJs": true,
            "moduleResolution": "node",
            "allowSyntheticDefaultImports": true
        },
        "includes": [
          "./src/",
        ]
    }
    

    在之前的打包配置里面,babel 实现的功能主要有两项,包括:编译 jsx 语法(preset-react)和 将晚进的语法编译为 es5 语法(preset-env),从而实现更好的兼容性。而 TypeScript 编译器同样可以实现这些操作,那么如果 babel 配置没有其他特殊操作(比如编译其他特殊语法),那么完全可以使用 TypeScript loader 替代 babel。

    tsconfig 文件里面可以配置编译器的各种选项。如果类型检查的时候,因为引入的组件没有 default export (通过 module.exports 输出),可能会报错,那么配置allowSyntheticDefaultImport 可以让 ts 忽略引用报错。

    文件转换

    源代码文件

    从 .js 迁移到 .ts,主要是添加各种类型声明。

    一些小 tips:

    • 事件类型(event):可以使用 React 事件注释:
    export type InputEvent = React.ChangeEvent<HTMLInputElement>;
    export type ButtonEvent = React.MouseEvent<HTMLButtonElement>;
    
    • 组件类型(element):组件可以用 JSX.Element 标注。
    • 组件方法声明问题,在 React 组件里面,有的时候会直接在 constructor 里面对创建的对象绑定方法:
    constructor(props) {
      ...
      
      this.foo = () => {
        ...
      }
    }
    

    而下面这种方式是将方法声明给了该组件 class 的 prototype,然后在 constructor 里面绑定新建对象。

    constructor(props) {
      ...
      
      this.foo = this.foo.bind(this);
    }
    
    foo() {
      ...
    }
    

    这两种写法对于程序运行没有实际的区别,但是第一种方式声明的方法并不在 prototype 上,所以类型检查无法将生成对象的方法和 class 方法对应起来,会报错。解决方法是按照第二种写法,将方法绑定到 class prototype 上即可。

    样式文件

    对于预处理样式(比如 stylus,sass,less等),需要相应的 declarations 文件,通过配置 css-modules-typescript-loader 可以帮助我们自动生成 d.ts 文件。

    1. 安装 css-modules-typescript-loader,在 webpack 配置其在 css-loader 之后处理样式文件。
    2. 创建一个 declaration 文件,声明预处理样式文件命名格式,因为我们的项目文件名字采用 .cm.styl 后缀表示,所以声明如下:
    // declarations.d.ts
    declare module '*.cm.styl';
    

    相关文章

      网友评论

          本文标题:# 从 JavaScript 到 TypeScript,Reac

          本文链接:https://www.haomeiwen.com/subject/lqsmvctx.html