16.了解类型编程与类型体操的意义,找到平衡点

10/9/2023

在学习 TypeScript 时,很多同学可能会遇到这些疑惑:

  • 这些额外的类型代码,以及类型编程,对实际项目开发的帮助在哪里?我真的需要精通它们吗?
  • 这些工具类型看起来真的好烧脑,并且它们并不能让我的网页运行得更快,让我的 Node 服务并发更高,让我的网页 PV / UV 数据更喜人,我为什么需要了解它们?
  • TypeScript 的学习曲线是怎么样的?是否存在一个比较平衡的阶段,让我的投入产出比最大化?

所以这一节,我们不学习代码,只是来聊一聊 TypeScript 类型编程的学习意义。因为此时你已经具备了深入学习类型编程的前置基础,又马上要进入工具类型进阶部分的学习。那在挑战这座最高的“山峰”之前,我们很有必要利用这几个问题带你走一些常见的误区,让你能心无旁骛地坚定向前。

# 从类型编程到类型体操

你可能会注意到,上面我用了“类型编程”和“类型体操”这两个不同的词。这是因为我通常把 TS 中的类型操作分为这两类。对于类型编程,它是对实际开发中真的有帮助的类型操作,下限非常之低,比如其实我们就是简单地用个泛型,这也属于类型编程。而它的上限也很高,比如底层框架中让人眼花缭乱的操作。但我们不需要用一个具体的界限来进行划分,只需要知道,只要是真的对实际开发有帮助的类型操作,无论实现多么复杂,都能被归类于类型编程当中。

那么类型体操又是什么样的?在此之前,你可能看到过基于 TypeScript 类型实现的四则远算、斐波那契数列、象棋、Lisp 编译器这一类令人叹为观止的操作,这些就属于类型体操。但请注意,这个词并不是贬义的,相反,大部分类型体操的作者都是编程功底十分深厚的大牛,他们发明这些体操的意图并不是为了炫技,只是为了展示给萌新们新世界的大门,我个人也非常佩服能写出如此高阶类型运算的大佬们。这些体操虽然对实际项目开发的意义非常有限,但却可以从另外一个角度让你认识到 TypeScript 类型系统的图灵完备,以及在高手手里所表现出来的精妙技巧。

但是,如果你因为看不懂这些体操,或者想不出更炫酷的体操而感到焦虑,那就需要警醒一下了——类型体操绝不代表你的 TS 水平。我看到过很多因为掌握了各种类型体操表演引以为豪的同学,其中有相当一部分人在实际业务开发中,仍然是各种 any 与复制粘贴。这就是非常严重的本末倒置,你学习 TypeScript ,是为了帅气的体操还是为了更高质量的代码呢?

如果你掌握了所有的类型体操,你就能写好所有的业务代码吗?答案显然是否定的。类型体操就像是五年高考三年模拟,只要你愿意花时间,对着答案总是能看明白的,但你看完就能保证做出数学压轴题的最后一小问吗?类型体操绝不应当被作为 TS 水平的度量衡,在绝大多数情况下,我们对于 TypeScript 相关的技巧,都应该秉持着从实用性出发的角度来看待。类似的,还有盯着 TypeScript 源码读,类型编程还没入门就去刷 Type Challenges 等等误区,当你发现学习进度慢得感人,掉发进度快得吓人,真的不会怀疑人生吗?

我个人更偏向于实用主义,就像这本小册一直到现在,以及接下来的内容都是接地气的,不存在你学了却无处可用的知识。这也是我认为在学习一门编程语言/工具/框架时最应该先考虑的事情,一门技术,要么应当能够在当下或者可预见的未来给予你帮助,要么能够扩宽你的技术视野和知识边界(类型体操并不完全算),而类型体操对于新人来说除了徒增焦虑并没有任何意义。

现在我们可以来回答下开始的问题了。

TypeScript 带来了哪些帮助?太多啦,我只讲一个社区中还没见过有人提的点。我们书写的类型实际上也是逻辑,只不过是类型世界的逻辑,并且不存在于运行时。在我们书写实际的代码逻辑时,这些类型逻辑就像是飞机起飞前的预检(preflight)一样,在你的代码还没运行时就能够发现其中隐藏的错误。稳定性、代码质量、严谨性、可读性等等,其实本质都是这一能力。它们的确不能让你的页面性能更好或是业务数据更棒,但却能避免潜在的严重问题,比如白屏和塞满错误监控的 Cannot read property of undefined

对于 TypeScript 来说最重要的,其实是与 JavaScript 的紧密结合,类型能力是添加在 JavaScript 之上的,也就意味着我们不需要学习一门全新的编程语言来获得类型检查。同时,我们可以说它的学习曲线是相对平缓的,因为并不需要学习太长时间就能写出还过得去的 TypeScript 代码。但它的边际成本是明显递增的,也就是说,假如你最开始只需要花 3 个单位的精力和时间,就能提升 10 个单位的类型覆盖程度(用来衡量 TypeScript 代码质量的指标之一),后面可能需要花 10 个单位的精力和时间才能再提升 1 个单位的类型覆盖。

但你真的需要如此高的类型覆盖程度,以及愿意花如此多的精力时间吗?我的建议是,在你优化 TypeScript 代码的过程中,如果感到边际成本明显提升,重构工作开始有些吃力,那你很可能已经达到了一个临界值,也是该停下来的时候了。

而对于 TypeScript 的学习曲线,自然也存在着这么一个平衡点,它标志着你的投入精力和获得回报达成了相对的平衡,再继续投入更多精力也无法看到明显的效果。你是否要问,这本小册中是否也存在着这么个平衡点?当然也是,只不过是几乎全本的内容(笑)。相信我,这本小册中基本都是你现在或未来会需要的技能点。只有 Compiler API 部分稍显复杂,但我们也会讲得有趣好玩一些。而对你自己来说,这个平衡点其实可以非常灵活,随着你的学习深入,TypeScript 技能不断提升,将会越来越渴望更多的知识,那平衡点不就越来越高了?

无论如何记住一件事,不要逼自己学习,当你在某一节学习过程中感觉到容易分神时,那就是时候休息了,站起来活动下身体,打开窗户呼吸下新鲜空气,我会一直在这里等你回来。

# Type Challenges

最后,我们再来说下如何进一步进阶类型编程能力。Type Challenge (opens new window)是 antfu (Vue 团队成员,以及 Vite、Vitest、Nuxt 等知名开源项目的团队成员或作者)的作品,其中搜集了许多类型编程的题目,并且贴心地按照难易程度分为了 easy、medium、hard 三个等级。

虽然我并没有把每一道题都完成,但我仍然推荐想要学习更高阶类型编程的同学去花上一定时间看看。当然,前提是你已经对整个类型能力有比较清晰认知的情况下,只有此时 Type Challenge 才能为你带来正面作用。这本小册中并不会有过于复杂的工具类型讲解,如果你学完之后感觉意犹未尽,还想尝试更多复杂的类型编程,此时就可以打开它来上那么几题了。

请务必牢记,Type Challenge 是在已有一定类型编程基础后,用来进一步提高水平的方式,而不是你用来学习类型编程与类型系统的方式,务必分清其中的因果关系。

Last Updated: 10/9/2023, 5:43:25 PM