美文网首页
# 从 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