项目中使用 TypeScript 的一些感悟

7,345 阅读6分钟

上周发布了一款名为 Smartour 的工具,是完全采用 TypeScript (以下简称 ts)来开发的。抛开以前做业务的时候的不完全使用,这次实践可以算是我第一次真正意义上的使用 ts。由于写法上的不同,以及对不熟悉事物的新鲜感,在这次项目开发的过程中着实有着许多感悟,于是打算写篇小东西好好记录下来。

TS 能让人养成“先思考后动手”的好习惯

在以往的开发过程中,我的习惯总是“先想好一个大概,然后边做边想再边改”。这样的好处是动作比较快,顺利的时候效率会很高,但更多的时候是不断地推翻自己先前的想法,相信不少的人也有跟我类似的体会。

而使用 ts,可以在一定程度上减少这个问题。众所周知 ts 是强类型的语言,这也意味着它能有效制约开发者在开发过程中“随心所欲”的程度。就以定义一个函数的参数为例,可以看看我在写 js 和 ts 的思考方式上有什么不同。

写 js 的时候,我的思考过程是这样的。

  1. 首先这个参数是一个对象,这个对象的属性 el 是一个 css 选择器;而对象的属性 keyNodes 是一个数组,里面的元素是一系列的 keyNode
  2. 这个所谓的 keyNode 也是一个对象,它也包含了一个 css 选择器属性 el,以及一个绑定在 dom 元素上的事件参数 event
  3. 我会把这个参数对象以注释的形式写下来,以便记住它的具体定义。
/**
{
    el: '#demo-id',
    keyNodes: [{
      el: '.item-1',
      event (e) { console.log(e) }
    }]
}
 */
  1. 以后任何地方要用到这个参数,我都要手动保证参数的结构要和这个注释保持一致。

而换成 ts 的写法以后,我的思路是这样的:

  1. 首先这个参数是一个对象,这个对象的属性 el 是一个 css 选择器;而对象的属性 keyNodes 是一个数组,里面的元素是一系列的 keyNode
  2. 然后我会通过 interface 把它给定义好:
interface HightlightElement {
    el: string,
    keyNodes: Array<KeyNode>
}
interface KeyNode {
    el: string,
    event: EventListener
}
  1. 在需要用到这个参数的时候,只需要在定义形参的时候传入这个 interface 即可。万一参数结构或内容的类型有误,VScode 编辑器都会立刻给予提示,省去了手动检查的麻烦。
someFunction (param: HightlightElement) { ... }

可以看到,在写 js 的时候更多的是“自己和自己约定,自己判断是否遵守了约定”,而 ts 则是“自己和自己约定以后,由第三方(编辑器)去判断是否遵守了约定”。这样的好处是除了老生常谈的减少错误之外,更多的则是对思维上的良性约束。这种良性约束能够让我们在思考的阶段就定义好接下来要做的一系列事情,在操作的过程中如果发现任何问题也能够在第一时间溯源回最初思考的起点,排查问题的时候会更加高效。

TS 拥有自成文档的特性

在写 js 的时候,我们依赖注释去判断某个变量或参数的类型、结构和作用。如果没有了注释,只能通过阅读源码和不断调试去搞清楚当中的细节。许多人在接手他人项目的时候都会有这么一个经历:“为什么不写注释!这个函数写的啥!这参数又是啥!”没有注释的 js 代码是让人崩溃的,但是写注释不仅需要时间,更考验一个人的概括能力。说了等于没说甚至误导性的注释,也是足够让人崩溃。

在 ts 中,除了注释以外我们还有另外一个选择,就是查看某个变量或参数所对应的 interface 接口定义。在 interface 中我们可以很直观地看到参数的结构,内部属性的类型,是否为可选等详细信息。再加上VScode 的智能提示及跳转,不管是查看他人的代码还是维护一个历史项目,都能更加方便和规范——毕竟写接口往往比写注释要顺手,看接口往往比猜代码要稳妥。

说到自成文档的特性,我也联想到了另外一个热门技术 GraphQL。借助 GraphQL 社区配套的一系列工具,调用方在调用接口的时候就能直接读到接口的标准定义;而接口的开发者也不需要额外编写文档,在定义接口的时候其实就相当于把文档也写好了。

自成文档的特性对于多人维护的项目来说是非常有用的,它能够大大降低项目当中沟通和理解的成本。但是这句话也有一个前提,就是开发者要遵守并合理工具当中的约束规范,如果一个接口的任何参数类型都是 any ,那么也就失去了使用 ts 的意义。

TS 能够降低搭建环境的时间成本

为了同时使用 js 新颖的特性以及兼容陈旧的浏览器,我们往往会借助一系列的工具去搭建一套开发环境。也许我们已经习惯了 webpack + babel 的开发方式,可是又有谁能够保证自己在不看文档的情况下能够自己去搭一套呢?且不说这些工具各有着复杂的文档,就算好不容易把环境搭好了,还会发现有着更多“最佳实践”。改来改去花了一天时间,才终于算是完成。

作为 js 的超集,我们可以在 ts 中放心使用 js 的各种高级能力。由于自带命令行工具,我们不再需要去研究 babel 或者各种 preset-env 插件,只需要指定需要构建的版本,ts 命令行工具就会自动为我们生成对应版本的 js。

当然这并不是说有了 ts 就能够完全抛弃构建工具了,在构建复杂应用(如包含各种静态资源,跨格式文件引用)场景的情况下还是离不开构建工具的,且在未来很长一段时间都会维持这种状况。但是秉承着“多一事不如少一事”的原则,只要能够减少哪怕是一个工具的使用,对开发者来说都是有好处的,毕竟我们都期待着某一个能够只管代码不管环境的日子。

尾声

由于不是 ts 的资深玩家,以上的碎碎念都是作为一个初学者个人的新鲜感。在工作的这些日子里,也深刻体会到永远没有百分百理想化的东西。ts 固然是好,但也需要辩证地看待它。我们是否真的需要 ts?它是否真的能够提高我们的生产力?它是否真的如他人描述般理想?这些问题都需要经过实践才能回答。说到底 ts 只是一个工具,什么时候用它,怎么用它,还是取决于具体的场合。一味地尬吹或者否认其他的东西,只能说明思想还是太狭隘了。