【译】使用 TypeScript 两年后-值得吗?

原文地址:https://ecom.software/en/after-two-years-with-typescript-was-it-worth-it/

作者:Kamil Zagrabski

差不多两年前,我在一个创业团队中开始了一个全新的项目。用到的全都是类似Microservices,docker,react,redux这些时髦的东西。

我在前端技术方面积累了一些类似的经验,因为在更早的一年前我带着20多名前端开发人员编写了一个非常大的react应用程序。这对我来说非常具有挑战性。当时我们遇到了很多问题:模型内聚的问题,代码库的增长,复杂且难以维护的api,接口不一致,难以跟踪运行时异常。

在开始新项目之前,我决定找到解决这些问题的方法。我想也许我们遇到的这些问题是因为语言本身有点过于灵活和宽泛导致的。你输入的内容几乎没有限制,再加上没有编译阶段,没有约束和运行前代码验证,这可能导致你的包存在严重错误。

然后我接触到了Flowtype和TypeScript。经过短暂的评估后,我决定选择TypeScript,并且一直用到现在。在两年后的今天,我可以告诉你 - 决定使用TypeScript对项目和我的职业生涯来说是个不错的选择。但是,如果你认为TypeScript开发人员的生活总是称心如意的,那么你最好继续阅读。

在本文中,我不想详细说明TypeScripts的功能或深入项目设置。互联网上有很多很好的资源( 例如官方TS文档:https://www.typescriptlang.org/docs/home.html )。当然,这篇文章也不是初学者的入门引导。

这是一个关于在使用TypeScript日常工作中感受到的优缺点的总结。我想描述一下我使用TypeScript的最糟糕体验,另一方面,我也要说一下我认为最有用的功能。所以本文都是关于利弊好坏的权衡,让我们开始吧。

首先要做的事 - 配置

正如我所提到的,我对react和redux有一些经验,所以我想利用这些优势,在新项目中使用类似的(自定义)配置。比如 - webpack,babel,npm scripts,jest,linter这些通用的东西,只需要额外做一件小事 - 支持TypeScript。

如果你现在处于同样的境遇 - 我确切的告诉你:它不仅仅是在webpack配置中加一个loader。必须为TS提供一个声明,用TSLint替换ESLint,集成TypeScript的loader和babel的配置,将TS插入Jest(测试平台)。

一些操蛋的事情马上就会发生。TS配置并不好搞,“简单的复制并测试”这种策略并不是上手的最佳方法。

在将tsconfig.json放入项目之前,最好仔细阅读文档。

此外,Jest(转换,模块映射器)和css模块存在一些问题。可能你迟早会面对它们。并且不要认为,你现在可以扔掉babel - TypeScript不会提供任何polyfill来让你使用那些牛批闪闪的新语法和功能,也不会将你的新API转换为旧浏览器可以理解的代码。

所以我的建议是 - 如果可以的话,你应该使用一些入门工具或支持TS开箱即用的CLI(比如 angular cli),以避免无休止的项目配置。

类库支持

另一个非常不愉快的经历与TypeScript支持的类库数量有关。

通常,如果你是某个人npm包的作者,你可以随时使用有效的JavaScript包。有时,您还会公开包的ES6源代码。如果你准备将库用于TypeScript,你必须提供类型定义。简单来说 - 是一个具有每个模块,命名空间,类,方法,函数等的声明的文件,TypeScript使用者需要用到这个。TypeScript模块只能使用定义中描述的内容,并且只能以声明中指定的方式使用。遗憾的是,通常源代码和声明之间没有严格的联系。并且它们可能还是不正确或过时的,或者根本就没有。

就个人而言,我没有找不到声明这样的问题。大多数流行的库都有自己的作者或社区准备好的类型定义。如果您使用的包没有这样的文件 - 那就换一个,相同功能的npm包多的是。不过你可以搞一个“假的”声明文件,或创建一个真实的声明文件并发布出来,以此为开源社区做出贡献。

不管怎样,还有一个更严重的问题 - 正如我之前提到的,一些声明是不正确的或过时的。如果你遇到这样的问题,没有简单的解决方案。你可以使用声明能正常工作的之前的版本,自己修复并贡献出去或等待作者来解决。有时候他们会及时修复,有时候就没那么快了。

顺便说一句,我是一些简单包的作者,相信我,即使想做好,但是我还是常常忘记将新功能与其类型定义同步。

日常工作

现在该轮到高兴点的部分了。一旦你配置了项目并选择了具有良好TS支持的库,就可以体会到类型语言的强大了。如果你没有这种语言的背景,一开始可能有点奇怪。TypeScript中有许多功能在当前的JavaScript语法中找不到。让我们谈谈其中对我来说最有用的那些。

类型

如果大家所想,TS最常用的功能是静态类型。没有使用严格类型校验也就没有使用TypeScript的意义。当然你可以使用宽泛的“any”类型,这意味着“我不关心那个东西的类型,它可能是一个数字,它可能是一个字符串数组,只管用就行了”,严肃脸,如果你想用这样方式编码,那还不如用回旧的JavaScript。

类型将帮助你更快,更安全地编码。你可以告诉编译器“这个常量妥妥的是一个数字”,如果你尝试将其用作数组或字符串,TS编译器将始终提示你输入错误。基本上,你仍然可以使用你的代码做任何你想做的事情,就像常规JavaScript一样,但现在你的操作比以前更安全,更易理解。

TypeScript中有几种基本类型和一点点跟它们相关的高级类型和技术。

下面你可以看到一些基础的但非常强大的东西,对于更高级的类型,请访问文档:https://www.typescriptlang.org/docs/handbook/advanced-types.html

除了众所周知的类型,如数字或字符串,TypeScript还提供了枚举类型。

您可以使用内置类型,如Date或Error。尝试代码提示,以实现更快,更安全的编程。

接口

如果你认为类型是“颠覆者”,那么你对接口有什么看法?接口可以帮助你编写更好的代码,因为它们最终允许你定义对象之间的约定好的实现方式。我创建了很多接口。他们无处不在。有时我专门为接口写一个文件,因为这样是值得的。

我主要用它来描述对象,类,函数和参数的形状。你可以在模块之间共享它们并像处理源代码中的实例一样对待,不过要记住 - 运行时接口不会出现在代码里,这一点很容易忽略。这就是为什么有些情况下使用类而不是接口(如使用Angular Dependency Injection)更好。让我们看一下接口的一些真实例子:

在左边 - 返回类型的错误实现。在右侧 - VS Code 立即通知你代码中的错误。

在左侧 - 一个类错误地实现了用户扩展的接口(参见上一个屏幕)。在右边 - 描述错误信息..

ES6中有类,所以你可能之前用过它。但是在TypeScript类中有一些额外的功能,可能EcmaScript的未来会实现这些功能。在TS中,您可以定义抽象类,你可以将类的属性描述为静态,私有或只读,您可以扩展类并使类实现接口(没毛病)。我不会比较TS类和ES6类之间的差异,因为最终它们都会产生类似的JavaScript代码(在编译和转换之后)。在TS类中,只是用优雅而有效的方式封装要使用的类,它们与其他语言实现(如Java)非常相似,这会产生一些影响(更多关于“代码审查”部分的内容)。看一下例子就能知道怎么用TypeScript和优秀的代码编辑器配合来让你的工作更容易。

当然,TypeScript中还有很多新东西,比如泛型(你会使用它们),枚举(对于内部事物可能会用到),命名空间,JSX支持等等。但你一开始不需要知道的面面俱到,只需使用上面提到的基本功能,你将看到,你的代码质量得到了提高。

使用TypeScript,你可以使用抽象类等功能。有关抽象类的更多信息:https://www.typescriptlang.org/docs/handbook/classes.html

TypeScript支持private,public和protected方法,只读属性。类可以实现接口或扩展其他类。

代码质量

我刚才提到代码质量了吗?当然提到了,因为我们都关心代码质量(除此之外还有客户需求,截止日期和排期,以及...)。

那么为什么应该使用TypeScript呢?(在代码质量这个层面)

  • 代码中没有与参数或变量名的拼写错误相关的一些非常烦人的运行时错误

  • 您可以建立清晰明了的对象之间的约定

  • 不用hack的手段就能实现类似在class中使用private的事情

  • 有来自编译器的即时反馈,很多错误都是在编译阶段捕获的,而不是在运行时

  • 让非JS开发人员更容易阅读和理解代码

  • 你可以使用JavaScript未来版本中的功能

  • 为单元测试编写mocks,stubs和fakes要容易得多,因为你知道他们的确切接口。

此外,由于出色的IDE支持,编写可维护代码要容易得多。老实说 - 即使你单独写一个不大的应用程序,几周后你也会忘了你必须传给服务的参数类型或新创建用户包含什么样的数据。你当然可以翻源码,过一遍代码然后找到有用的信息(假设你的代码总是简洁的),但在你喜欢的编辑器中将鼠标hover到函数名上就能看到你要的信息岂不更好?例如,它接受“age”,这是一个“number”,并返回具有“age”和“name”属性的用户实例。

代码审查是我想提到的另一件事。当你在小团队中工作时,有时候你是唯一的前端开发人员,在做.net或Java的同事真的不喜欢看原生的JavaScript。由于语言的动态和简洁性,他们会觉得可读性很差,没有类型意味着没有提示。例如 - 名称为“user”的对象具有“ID”属性,但ID是数字还是字符串?如果是一个字符串,为什么你只需要调用“toString()”就可以了?如果是一个数字,为​​什么你刚刚在它前面添加字符串“id_”呢?TypeScript代码看起来很像其他流行的类型语言,并且你有可能将获得更好,更准确的代码审查。更好的代码审查意味着更好的代码,这个不需要我再多说了吧。

左侧 - TypeScript中的代码。右边 - Java中的代码。如您所见,语法非常相似,这意味着比起原生的JavaScript,Java开发人员应该更容易理解你的TypeScript代码。

学习曲线

最后关于TypeScript我还要多说一点。与往常一样,当你尝试新事物时,会有一些学习曲线。放到TS下看,它不是非常陡峭,但是要避免TypeScript和新框架一起用,这两样加起来就会让学习曲线变得足够陡峭。特别是在大型或缺乏经验的团队中。这就是为什么我两年前选择了这个项目作为我的第一个TypeScript应用 - 我对react那套技术栈非常熟悉,所以这是一个学习一种有前途的新语言很好的机会。我敢保证,如果我同时选择了一个新框架(比如说Angular)和一种新语言(在此指的是TypeScript),我会被按在地上摩擦。

总结

我会向你推荐TypeScript吗?当然会。它将帮助你在更短的时间内写出更好的代码。IDE支持现在非常棒,社区充满活力,具有TS定义的库的数量很庞大而且还在不断增长,用过的程序员都说好(来自编译器的快速反馈)。这是我所知道的用于创建现代和可扩展的Web应用程序(当然还有Node.js服务)的最佳工具。请记住上面提到的一些缺点,解决了它们就能深入探索静态类型语言的多彩世界了。

Last updated