浅谈Typescript前端体验
最近两年,Typescript
逐渐成为前端项目的标配,甚至出现了Typescript
即将接管JS世界的段子。大部分前端开发者也陆陆续续从React
、Vue
、Angular
开发生态中接触到了TS,一时间关于Typescript的教程大量出现,不过大部分教程更关注Typescript
的类型系统。本文将对TS
进行一个简单的梳理总结,旨在让 TS
开发者换个角度了解Typescript
。读完本文后,我们应当能对Typescript
有以下认识:
Typescript的设计初衷
Typescript的两大特性
Typescript为我们带来了什么
Typescript还为我们带来了什么
Typescript如何更利于构建大型应用
关于Typescript的使用建议
Typescript的设计初衷
JavaScript的段子:动态一时爽,重构地雷场。
最近这些年,随着硬件性能、前端自身快速发展等因素,前端应用程序的体量与复杂度直线上升。而在大型应用的开发过程中,JavaScript动态语言与弱类型的语言特性,随着成员数量的增加、代码体量的增长、业务场景复杂度的上升,文档及单元测试的缺失等情况的出现,导致了以下问题:
类型错误多,bug率居高不下。
缺少文档、新成员理解应用逻辑困难。
维护成本高、可扩展性差的困境。
在软件开发过程中,随着需求的变化和系统规模的增大,我们的项目不可避免地会趋于复杂,最终造成了项目中后期进度缓慢的情形 。如何对软件复杂度及其增长速率进行有效控制,便成为一个日益突出的问题。Typescript正是在这种情况下,应运而生的。
Typescript的维基百科词条
TypeScript 起源于 Javascript 在微软以及客户中开发大型应用中遇到的缺点。处理复杂 JavaScript 代码带来的挑战使他们需要自定义工具来简化组件开发流程。
TypeScript 开发者寻求一种不破坏现有标准兼容性和跨平台支持的解决方案。知道ECMAScript标准为未来基于类编程提供支持后, Typescript开发便基于此方案。这形成了包含一组新的语法扩展的一个JavaScript编译器,一个基于此提案的超集,可将TypeScript语法编译为常规的JavaScript。
TypeScript不仅包含JavaScript的语法,而且还提供了静态类型检查以及使用看起来像基于类的面向对象编程语法操作 Prototype。C#的首席架构师以及Delphi和Turbo Pascal的创始人安德斯·海尔斯伯格参与了TypeScript的开发。
Typescript的两大特性
维基百科上关于Typescript的介绍,提到了两个关键的词:静态类型检查、面向对象。
前端在经过Flow
、Typescript
、CoffeeScript等短暂的类型检查之争后。Typescript
在开发速度、协作成本、维护成本上的出色表现,实践过Typescript
构建大型应用的团队,几乎是一边倒的从JS转向了TS。具有代表性的:Ant-design
、Angular
、Vue-next
从最初的JS版本切换到了TS版本。
有意思的是,为什么React不使用Typescript?
静态类型检查
下图即是TS的类型系统,市面上已经存在大量解读类型系统的教程,在这里我们不再赘述
面向对象
在2018年年初,我们使用Typescript
重构React前端,很快我们与TS进入了短暂的蜜月期,低级的错误大幅减少。但随后我们就发现,如果上述内容就是Typescript
的全部内容,Typescript
对我们来说就是一个玩具,一个高级玩具。
前面说过,随着代码体量的增长、业务复杂度的上升,文档及单元测试的缺失,人员流动等因素的出现,功能理解、模块冲突、代码难以维护的问题,并没有随着静态类型检查的出现而大幅消失。
虽然逐渐沉淀出容器组件、展示组件、业务逻辑与UI分离等等模式,我们还是会遇到改一发而动全身的bug,新成员理解困难、老成员的模块各种冲突问题,逐渐我们感觉到Typescript似乎并没有它宣称的那样强....
Typescript号称适合构建大型应用,我们开始反思这句话是否正确。在github上我们注意到,vscode的源码便是通过Typecript编写的。既然Typescript能搞定IDE编辑器这种复杂的应用,我们期望从vscode的源码中,找到解决方案。
刚开始我们对vscode中的这种写法很困惑,并且对大量的implements
、abstract
、private
protect
设计感到陌生。经过大量的面向Goole编程,我们逐渐注意到Typescript的第二个特点,面向对象:封装、继承、多态。
封装:隐藏数据和功能实现细节,避免被外部修改,而导致误用。
继承:子类拥有父类的所有属性和方法,从而实现了实现代码的复用。
多态:同一个行为具有多个不同表现形式或形态的能力。
用一句话描述面向对象:将功能拆分为职责单一的功能、通过封装将功能隔离开来,再通过组合的方式去构建大型应用。
面向对象是个比较大的领域,我们将通过下文中的的一个例子,简单的讲下对面向对象的三大特性
Typescript为我们带了什么
低级错误的查找定位
rollbar 于 2018 年统计了前端项目中Top10 的错误类型:
其中有 7 个是类型错误(TypeError),这对Typescript来说就是送分题。
阅读代码能力的加持
vscode中有一些非常方便的代码阅读技巧
查看用法 悬停:读取interface同时显示注释
转到定义 Ctrl + 单击、转到符号定义的源代码 F12。
窥视定义 Alt + F12:调出一个窥视窗口,显示符号的定义。
转到参考 Shift + F12:显示相似字符的所有参考。
智能提示自动补全
IDE很早就有了自动补全功能,在有d.ts类型文件后,可以自行编写类型库,供IDE识别,最具代表性的便是:www.typescriptlang.org/dt/search?s…
重构能力的增强
提取函数
提取变量
以上内容,我们可以总结为:
类型错误的静态检查
代码可阅读性的提高
编写速度的加快
可维护性的提高
Typescript还为我们带来了什么?
Typescript的静态类型分析,目前是影响甚广。而Typescript的面向对象,前端开发者普遍没太大感受。与后端发展的时间相比,前端快速发展的时间太短,以至于前端整体并没有沉淀出完整体系的设计模式、设计原则与**建模。**借助Typescript的特性,刚好使我们可以借鉴其它领域。
UML建模
UML主要使用图形符号来表示软件项目的设计,使用UML可以帮助项目团队沟通、验证功能的设计。
类图:
时序图:
用户管理-时序图
UML以图形符号的形式,填补了一部分的设计文档与使用文档。
设计模式与设计原则
在Typescript出现之前,部分面向对象的设计模式也可以用JavaScript模拟出来,但因为缺少接口interface、访问限定修饰符、抽象类几个概念,面向对象中的封装与多态在JavaScript中一直是一个难以理解、难以模拟的概念,而Typescript的出现恰好补上这缺失的一环。
最近几年,在Typescript流行开来的同时,函数式编程也随着Redux等的流行而火热起来。在这里,我们无意争论两种编程模式孰优孰劣。我们需要的是保证应用构建的强壮与可维护。在使用Typescript的过程中,我们决定破界,去尝试前端不熟悉的面向对象。由于面向对象是个比较大的领域,我们在这里不详细介绍面向对象的内容,有兴趣的同学可以通过底部设计模式的链接了解一下面向对象。
Typescript更利于构建大型应用
如果问Java、C#的开发者,静态类型检查有何意义?
标准答案是“静态类型更有利于构建大型应用”。
Typescript与JavaScript在开发大型应用的进度对比,如下图所示:
我们在前面的Typescript
设计初衷中,提到在大型JavaScript项目中后期,经常我们面临的3个问题:
-
类型错误多,bug率居高不下。
-
缺少文档、新成员理解应用逻辑困难。
-
维护成本高、可扩展性差的困境。
Typescript是如何解决上述问题的?
其一、静态类型检查可以尽早构建失败。一旦编写代码时发生类型不匹配,在编译阶段前、中阶段均可发现。
其二、静态类型对阅读代码是友好的。针对大型应用,方法众多,调用关系复杂,不可能每个函数都有人编写细致的文档,所以静态类型就是非常重要的提示和约束。
其三、UML建模语言,弥补了部分设计文档与说明文档,同一套的设计模式,使得理解功能变得容易。
其四、借助面向的设计思想,隐藏实现细节,加强功能的内聚性。控制接口暴露粒度,来降低功能间的耦合度,达到容易扩展的效果。
其五、静态类型其配合IDE的重构功能,维护困难系数直线下降。
结合Tyepscript、React接触面向对象OOP与函数编程FP,我们总结了如下体验:
在应用设计层面,OOP有着一套完整的设计体系,可以应对模块可扩展性、业务的复杂性的挑战。
在细节实现层面,不要为了OOP而OOP,OOP不是万能的。
在处理数据流时,FP有着独一无二的优势。
关于使用Typescript的建议
我们的强烈建议是:Typescript是一种语言,包含两部分内容:静态类型检查、面向对象。如果你已经尝试了类型系统,并且已经熟悉了JavaScript的各种特性,不妨学习下面向对象,或许能更好的掌握Typescript这门语言。
在接触面向对象之前的两点提示:
设计原则、设计模式是一种编程范式,是跨语言、跨框架的。
强类型的语言特性,带来了一种新思维习惯。
结语
通过前文所述,我们应该知道:
Typescript的设计初衷是为了应对大型应用中JavaScript的复杂性而设计的。
Typescript的两大特性:静态类型检查、面向对象。
Typescript作为一种强类型语言,不仅有静态类型系统,更我们带来了一套完整的控制功能复杂度的技术体系。
如果你是一名中高级前端,建议在拥抱函数式编程的同时,尝试跨界学习下面向对象编程。