你可能忘记了的typescript基础

183 阅读10分钟

在平时的工作中,公司往往会给我们开发好各种各样的教授架项目以及相应的脚手架工具可能让你连教授的本身的全貌都看不到。在自己做项目的时候,为了节省时间,可能也会寻找完善的脚手架工具完成项目的创建。

久而久之,我们都可能忘记了基础的技术原本是什么样的。我也是突然感觉到这问题,所以想要在了解一遍typescript的开发配置最佳实践基础(本篇文章不会介绍语法基础)。强如winter也会重学前端,我们何不学而时习之呢?

快速回忆

先快速思考,简单项目中配置typescript应该怎么做。

回答:

npm install typescript --save
tsc index.ts

回答正确,这样就能编译ts文件为js了。但是缺了点什么,对吧。

tsconfig.json编译配置

tsconfig.json文件是指定将要编写的项目按照什么配置进行编译。这样的定义我也认为没有解释清楚,但是看了这个文件的内容我就明白了。我认为这个就不需要死记硬背,能看懂,需要写时会查找文档就够了。

    compilerOptions // 编译选项,即规定ts编译器如何将ts编译成js,比如指定生成文件的目录,指定生成的js版本,编译过程中使用的库列表,是否编译js文件等等。
    files,include, excludes // 需要编译的文件列表,可以使用通配符等设置范围
    extends // 继承的配置文件
    compileOnSave // 是否在保存时自动编译

其中的compilerOptions文档传送门:编译选项 · TypeScript中文网 · TypeScript——JavaScript的超集 (tslang.cn)

eslint代码检查

eslint是对编程规范进行检查,我们团队使用的编程规范是在继承arbnb规范的基础上进行改进。 简单介绍一下eslint的常用配置:

// .eslintrc.js

module.exports = {
    extends // 属性值可以是一个字符串或者字符串数组,数组中每个配置项都会继承它前面的配置。
    env // 这个配置用于指定环境,每个环境都有自己预定义的全局变量,可以同时指定多个环境。
    globals // 脚本在执行中访问的额外全局变量,也就是在env指定的全局变量之外自定义的一些全局变量,可以指定是readly或者writable。
    parser // eslint会对我们的代码进行校验,但是校验的不是源代码,而是经过parser转换后的 Estree(一种AST规范,就暂时先理解成AST)。
    parserOptions // 允许我们自定义一些校验规范
    plugins // 插件列表,插件是对extends指定的预设eslint规则的扩展,对于大型项目,可能会对eslint进行特殊定制,在eslint的现有规则找不到合适的时候就会使用插件来实现。
    rules // 这个地方是对eslint具体规则的配置,这其中Standed是比较松散的社区版配置,而Airbnb的配置是比较严格的,如果我们使用了这个作为基础配置,就可以在rules里面进行修改或者覆盖。
}

现在如果我创建一个ts项目,至少能够保证我书写规范和编译完成了,向企业级的开发由迈出了一步。

TypeScript和工程化进阶

当我了解完使用ts进行高质量开发的基本要求,就觉得还是有很对疑问,比如在开发中我们不可能写完代码就执行一遍eslint来进行代码检查然后再执行一遍tsc来进行代码编译吧,这不符合快速开发的标准吧。

这时候会想起前端工程化的内容,前端开发也经过了一个不断发展的过程,从三件套的刀耕火种时代是如何发展到如今大火的webpack时代,当然还在继续发展,比如比火更火的vite(我还没深入研究过)。

所以,要想不手动的执行这些,肯定是要和npm,webpack等工程化的工具相结合使用。也只有实现了工程化,才能实际应用到实际开发中。

TypeScript+Webpack

有了ts基础,再加上已有的webpack基础,现在就只需要补充一下如何在webpack中结合typescript就可以了。之前的文章中写过如何从零配置webpack(webpack基础:从零搭建项目框架 - 掘金 (juejin.cn))。

说起来,其实我也纠结来着,因为其实plugin真的和loader会有重合的内容,同样的功能,可能有不同的配置。

网上搜一下关于ts+webpack关键词,就会出现ts-loader,awesome-typesscript-loader,babel-loader,@babel/preset-typescript以及其他一些五花八门的配置和关键词。而且基本就是说一下怎么配置,稀里糊涂的骚操作,我真的会醉。

梳理

到底这些五花八门的方案之间有什么联系和区别呢,他们到底又是什么意思呢。于是我肝了一晚,总算明白了一些。

ts-loader

首先这家伙肯定能完成对ts的转换。因为在官方文档里面就有关于它的配置的详细写法。

ts-loader是使用tsc进行编译的,所以我们在项目根目录下面的tsconfig.json同样会在它工作的过程中起到配置作用。

和tsc不同的是,ts-loader可以通过 transpileOnly: true 进行取消代码检查,直接进行编译。

不过写ts不进行代码检查好像有点奇怪,虽然vscode可以弥补这一点,但是不是所有前端都是用的vscode。所以在ts-loader的官方文档中,又给出了另外一个plugin,用来单独进行代码检查,fork-ts-checker-webpack-plugin,它会运行在一个单独的进程里面,这样将检查和编译分别进行,就加快了编译速度。

总结一下,就是ts-loader+TypeScript可以完成编译,再用fork-ts-checker-webpack-plugin单独进行代码检查,再加上如果是用的vscode(当然其他编辑器肯定也会提供插件)编辑器带有的代码提示功能,看起来就是完美的ts方案。

babel-loader

babel-loader是一个js编译器,可以将高版本的js编译成低版本的在浏览器可以运行的js。

所以,原本babel和ts是两个不同用途的编译器,一个用来编译ES,一个用来编译ts。虽然实际上,ts也可以编译js,但是我们先忽略这种情况,因为如果这样杠下去我还可以提前说babel还支持jsx等。

但是自从babel7开始,它支持ts的编译了。也就是说,现在ts编译器变成了babel的一个子集。

但是babel对于ts的支持是通过将ts转换成js来实现的,也就是它把ts看作es,只不过添加了很多其他特性的es,这些特性单独处理就可以了。所以,他也没有了类型检查。

我们写ts,你总把类型检查去掉怎么办呢。好在ts可以在配置中设置: noEmit:true, 这样可以让tsc不输出文件只进行类型检查。当然也可以使用上面说的那个类型检查器单独进行检查。

总结一下:babel-loader(7以上版本)+@babel/preset-typescript以及一些增强特性的插件,可以完成typescript编译,在使用tsc进行代码检查就可以了。也可以使用其他的检查工具进行代码检查。

ATL

ATL就是awesome-typescript-loader,这个是一个曾经的最佳实践,它通过将代码检查和并行编译功能封装在一起,完成了一个包就能进行编译的效果。它可以看作是ts-loader+类型检查自己的封装。是一个优化版的ts-loader。完全可以当作ts-loader的替代品。

但是它的类型检查是有疏漏的,所以使用起来基本需要另外做类型检查,将原本的禁用。

结论

所以以上几种方式可以单独使用或者混用都可以。主要是babel和ts本来就是不同的概念。

但是一旦混用性能就会受到影响。所以最好只用其中一个来做就可以了。

但是实际上,企业级的项目需要各种功能,框架,一旦项目架构丰富起来之后,就会有更多种类的文件需要进行处理,不是只有ts需要处理。这个时候,tsc的局限性就显示出来了,babel就会因为自身大量的插件优势而胜出。所以一般在公司项目中就需要使用babel就可以了。

如果是一个ts写的SDK项目,那肯定是首先tsc,因为配置简单又好维护。

Typescript和React以及Vue

React和Vue为了方便开发者使用,提供了一系列的工程化工具和语法糖来使得开发方式变得更加简单和容易上手。

比如jsx语法和.vue文件,之前我都是直接使用官方提供的cli工具傻瓜式使用,一开始项目是不支持ts的,后来需要支持ts的时候,才只能去肝原理。

React

先说结论,和上面的一样,关键在于ts的多样性配置,还是比较ts-loader和babel之间的区别而已。

如果使用的preset-typescript进行的ts编译,那我们就需要再使用preset-react处理一下js。

总体而言,随着jsx的编程思想广泛被接受,React对ts的支持非常友好。ts和react的结合也比较简单。

Vue

相对而言,Vue的支持麻烦一些。

// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
  module: {
    rules: [
      // ... 其它规则
      {
        test: /.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // 请确保引入这个插件!
    new VueLoaderPlugin()
  ]
}

这是普通的js项目中的vue配置。其中的VueLoaderPlugin插件是非常关键的,首先,你写的.vue文件看起来是一个文件,实际上三个文件,其实Vue可以有另一种写法,就是将一个.vue文件拆开成一个文件夹,里面分别是.js、.style(style代指样式文件)和.html三个文件。

这样,就可以接着说,VueLoaderPlugin的功能就是将你定义过的其他规则应用到.vue文件对应的模块中(上文说的三种文件)。

如果你使用的是css预处理器,在样式表中标注明确就可以了。同样的规则也适用于各种js的拓展语言。在Vue中,编译ts就是使用的ts-loader,这样相对来说要方便。这里ts-loader因为无法识别.vue扩展名,所以需要在配置中添加相应的配置以便vue-loader的plugin在处理的时候将.vue后面添加上.ts扩展名。

关于ts,还有许多需要了解的知识

通过一篇文章,把ts在工程化中的配置基本上梳理出清晰的知识了。

这些知识包含了原生的ts是如何编译成js的以及在前端实际开发中是如何通过其他工具结合进行编译的。最后具体讲解了ts如何与前端框架相结合,因为React和Vue是目前国内用的比较多的,所以以这两个为例子来讲解了。

关于ts和前端,还有很多知识需要我们不断的去梳理去总结。

希望大家也能多多了解自己正在使用的工具,知道自己写的逻辑是怎么编译的。