此前我写了几篇文章,关于 Electron,关于 Vue,创建项目的时候,我都默认选择了使用 TypeScript 的模板,不过我都加了一句话,初学者如果不想自己找麻烦的话,最好不要使用 TypeScript。原因呢,也很简单,因为不但用起来很痛苦,配置起来也很痛苦。
一、什么是 TypeScript?
TypeScript 是由微软开发的一个开源编程语言。它是 JavaScript 的一个超集,这意味着它包含了 JavaScript 的所有功能,并且在此基础上增加了静态类型检查和其他一些特性。TypeScript 的目标是开发大型应用程序,提供更好的代码组织、维护和协作能力。
以下是 TypeScript 的一些关键特性:
-
静态类型检查:
- TypeScript 最显著的特性是它的静态类型系统。开发者可以在代码中为变量、函数参数、返回值等指定类型。这有助于在编译时捕获潜在的错误,而不是在运行时。
-
类和接口:
- TypeScript 支持面向对象编程的类和接口。这使得开发者可以创建复杂的数据结构和封装代码,从而提高代码的可读性和可维护性。
-
模块系统:
- TypeScript 提供了一个模块系统,允许开发者将代码分割成独立的模块。这有助于组织大型项目,并支持模块化开发。
-
编译到 JavaScript:
- TypeScript 最终会被编译成纯 JavaScript 代码,这意味着它可以在任何支持 JavaScript 的环境中运行,包括所有现代浏览器和 Node.js。
-
工具和编辑器支持:
- TypeScript 拥有广泛的工具和编辑器支持,包括 Visual Studio Code、WebStorm、Sublime Text 等。这些工具提供了代码高亮、自动补全、类型检查和重构等功能。
-
兼容性:
- TypeScript 旨在与现有的 JavaScript 代码库兼容。它支持最新的 ECMAScript 标准,并且可以配置以兼容旧版本的 JavaScript。
-
装饰器:
- TypeScript 引入了装饰器(Decorators),这是一种特殊的声明,可以附加到类声明、方法、访问器、属性或参数上。装饰器为 TypeScript 代码提供了一种新的扩展机制。
-
高级类型:
- TypeScript 提供了高级类型,如联合类型(Union Types)、交叉类型(Intersection Types)、字面量类型、类型别名、类型断言等,这些特性使得类型管理更加灵活和强大。
TypeScript 的目标是让开发者能够编写更健壮、更易于维护的代码,同时享受现代 JavaScript 开发的所有优势。它在大型项目和企业级开发中尤其受欢迎,因为它可以帮助团队更有效地协作和管理代码。
二、使用 TypeScript 带来的麻烦
在项目中实际使用 TypeScript 的时候,会产生许多的麻烦,下面我来说说,都有哪些。
1. 编写代码
在写所有的代码的时候,都要声明类型,比如:
function printNumber(num: number) {
console.log(num)
}
上面的代码里,声明了一个 number 类型的参数,如果只是这种程度,远远算不上麻烦,比起能带来的好处如第一章介绍的来说,这点麻烦不值一提。
我觉得真正的麻烦在于,我们编写代码的时候,都不是孤立的。往往会结合很多的类库,或者框架。这时候麻烦就来了。很多类库、框架都是老牌的,那么这些是否都提供了对应的 TypeScript 版本呢?未必。
如果提供了 TypeScript 版本,那么类型定义是否都完整提供了呢?未必。
如果提供了类型的完整定义,那么是否提供了详细的使用文档呢?未必。
我举个例子,比如我在使用 Vue 3 开发的 Element Plus,这么有名的框架,当然使用 TypeScript 开发的,不过,看看这个:
<template>
<el-tree-select @onCheck="onCheck"></el-tree-select>
</template>
<script lang="ts" setup>
function onCheck(data, node, treeNode, event) {
//...
}
</script>
如果,用比较严格和规范的方式去编写,那么请问这个 onCheck
回调的四个参数的类型应该如何去声明呢?其实,这四个参数是 Element Plus 框架里的 ElTree 组件的回调,这个参数的类型,高度依赖了 UI 框架内部的类型定义,但是怎么导出这四个类型呢?太难了!
2. 项目异构
现在的项目结构一般都很复杂,每个不同的部分又使用不同的标准。举个例子,比如我的 Electron 项目,Node 的部分,遵循 node 的标准,甚至不支持 ES Module,而 Vue 的部分,遵循的是浏览器的标准,这两者显然就不一样,如果用了 TS 的话,那么显然需要两份配置。
这就给项目的配置带来了极大的麻烦,我折腾这么久,就没彻底弄明白过。比如,怎么让 node 的 TS 用一套规则,Vue 用一套规则,还要井井有条,还要集中调用,最好前后台还能共享一些类的定义。
另外,如果你的项目里有测试,测试又是单独的一套,而我既要测试 node 的代码,又要测试 Vue 的代码,那不得了,又要分裂了。
3. 工具链嵌套
比如在 Vue 的项目里,代码文件都是 vue 扩展名的,默认情况下 tsc 肯定是无法识别的,所以就要用到 vue-tsc,但是实际上,我们在编译的时候,用的又是 Vite,显然 Vite 内部也会调用编译的功能,那么在 Vite 的配置里和 TS 又是怎么交互的呢?
在我的 Electron 里,我用了集成式的打包工具 Electron Forge,这个工具会调用 electron
命令,里面又整合了 Vite-Plugin,里面又…… 就…… 俄罗斯套娃🪆,感受一下。
这一切,都让每件事情都变得格外痛苦。困难加倍。
4. 调试困难
tsc 这种命令,文档什么的我就不说了,调试是非常困难的,比如你要写个配置文件然后尝试运行 tsc 命令,但是输出了错误信息,你怎么判断哪条配置造成了问题呢?只能用控制变量法和排除法一条一条地尝试。这就很糟糕了。
三、解决办法
现在我解决这一类问题,也没有什么太好的法子,就是只能自己硬着头皮去看文档,所得是有的,就是很慢。
助力比较大的是,基于别人的项目模板去创建项目脚手架,但是这种预设的东西,终究不是完全符合自己心意的,比如 Vue 的脚手架和 Electron 的脚手架怎么合并成一个项目呢?要么用社区爱好者自己写的模版,要么就得自己研究。终究还是困难的。
第二个办法,就是从别人的项目里看,阅读别人的配置文件来学习具体的做法,比如阅读官方模板里的配置文件,我觉得就很有帮助,使用 AI 来辅助阅读,也是最近一个很好的法子。既然 LLM 那么强大,何不用来学习呢?
实际配置实践中,则是需要用到各种预制的配置,基于这个基础去补充或者改编,以减低工作量。
四、总结
本文介绍了使用 TypeScript 中的一些感想,简单介绍了什么是 TypeScript,有什么特性和优点,为什么要使用。以及实际使用中,带来的各种困扰。最后是博主尝试后做出的努力方向和解决方法。希望对各位有启发。