TypeScript 在 Slack 的实践

原文:https://slack.engineering/typescript-at-slack-a81307fa288d
本文非逐字逐句翻译,保留原意的基础上,对内容略作修改。

当 Brendan Eich 用了十天就创造出 JavaScript 的第一个版本的时候,他应该没有想到 Slack Desktop 如何使用他发明的 JavaScript: slack 基于一套 JavaScript 代码,完成了能够和原生代码交互,并且是跨 Windows,macOS 和 Linux 平台的多线程桌面应用。

管理大型的 JavaScript 代码库是有挑战性的。例如,我们需要不定期从 Chrome 里把 JavaScript 的 objects 传递给 Objective-C,并且需要从运行着 Node.js 的另一个线程收到回调,我们需要保证每一部分都能协调正常。任何小的错误都有可能导致桌面应用崩溃。为了实现这一目标,我们引入了 TypeScript(中文)(JavaScript 的类型超集), 并且很快意识到使用 compiler 的好处。不仅仅我们,在2017年 StackOverflow 开发者调查 中,TypeScript 是最受喜爱的编程技术的第三名。考虑到静态类型检查(static type checking)的吸引力,我们想分享一下我们的经历和实践。

静态分析带来的好处

在过去,我们用 JSDoc 来为我们的函数写文档,用注释来解释类、函数和变量的作用和正确用法。这可能会有问题,比方说,当我们阅读代码时,有可能很难理解某个 JavaScript promise 到底完成了什么。只能寄希望于代码的作者写了正确的文档,并且后来的人在修改代码时及时更新了文档。在一个有很多 modules 和依赖的复杂系统里,很有可能因为没有看原来对应的代码就给某个函数添加了破坏性的更新。

为了改善我们的境况,我们决定尝试一发静态类型检查(static type checking)。静态检查并不能修改代码如何运行,它只是分析代码并尽可能推断类型,帮助开发者在交付代码前找到潜在的问题。
静态检查器能够理解 Math.random() 的返回值是 number, 而 number 不能响应 string 的方法 toLowerCase().

更具体点,如果手动提供 types 类型文件,类型检查器就能更好地帮助人和机器理解程序本来应该怎样运行。
示例:为 user 对象定义一个 User interface, 并且假定在这个方法内要得到 user's age. 静态检查器就能分析代码并且警告了一个典型的错误:这里 User.details 有可能是 undefined.

需要注意到,运行时的代码没有被修改,也就是说静态检查器没有影响到最终的用户。上面的例子在运行时就像普通的 JavaScript(原文: vanilla-flavoured JavaScript).

一个聪明的静态类型检查器提高了我们对代码的信心,帮助我们在提交代码前更容易地找到错误,并且使代码更加自解释性。

将 Slack 桌面应用的代码库移植到 TypeScript

TypeScript 自带静态类型分析和编译器,就用它了。我们不需要修改原来任何代码就能使用 TypeScript, 因为 modern JavaScript 就是有效的 TypeScript. 这就意味着可以在继续开发新 features 或者在旧代码上修复 bugs 的同时可以尽早使用 TypeScript 的静态分析和编译器。

实践中,不用改变代码的同时打开静态分析和编译器就意味着 TypeScript 会立即尝试分析代码。TypeScript 会利用内建的 types 和第三方提供的 types 分析代码并指出以前没注意到并不易察觉的 errors. 如果 TypeScript 不能确定类型,它会给出一个 Any 来代替。

我们原计划是逐步移植,并且尽可能地为原有的 JavaScript 添加确定的 type 定义:增加 interfaces, 为 methods 添加 private 或者 public, 并且添加 enums 等。在这个过程中,我们收到了惊喜:

  1. 在移植过程中,我们发现了代码中一些小的 bugs. 和一些已经在使用 type checker 的开发者交流后,我们发现:写的代码越多,越有可能不可避免地出现拼写错误、假定一个 nested object 的 parent 一直存在或者使用了非标准的 error object.
  2. 我们低估了编辑器集成的强大能力。由于 TypeScript 的 language service 能够理解特定的 objects 能够用到哪些 properties 和 methods, 带有自动补齐的编辑器就可以提供基于上下文的提示,为开发带来便利。以前那些只能基于字面意思的自动补齐就显得太落后了。以前那些通过 google 再三检查哪些 events 是 Electron's BrowserWindow 可用的 events 的日子一去不复返了。TypeScript 的插件涵盖了 Atom Visual Studio Code Sublime 等主流编辑器。不用离开编辑器就能验证代码确实提高了我们的生产力。

如果考虑到未来代码的可维护性,TypeScript 生态圈也是值得称赞的。作为 React 和 Node/npm 生态的重度使用者,来自第三方的 type definitions 是一个很大的加分项。我们使用的很多库都是 TypeScript 兼容的。如果某个模块没有自带 type definitions, 那么也很有可能在 DefinitelyTyped 中找到。React本身就没有自带 type definitions, 但是仅需 npm install @types/react 就可以安装并且无需其他配置。
我们在开始转换的几天内就可以把 TypeScript 应用到所有的新代码中了,代码的稳定性和完整性因为 TypeScript 而大大受益。我们花了差不多六个月完成了为了桌面应用的代码添加注释。

更有信心地 commit 代码

为了强制的可阅读性和可维护性,所有阶段的代码都会经过 TSLint 的检查,这就意味着,在 Git commit 提交前,会自动检查代码能否通过我们限定的规则。我们现在不允许"implicit any" 等 TypeScript 不能自动推断类型的情况,也就是说我们现在要求所有的 Slack Desktop 的代码都要有清晰的 type definitions.
当 push 新分支时,Git 首先用 TypeScript 编译器跑一遍整个代码库,找出整个代码库结构性和功能性错误,并且把 async/await 等 modern features 转译成 ES2016 兼容的代码。当新开 Pull Request 时,代码所有的结构性依赖都是健全的,我们对此很有信心。

看上去还挺难的

对我们来说,TypeScript 带来的好处远远碾压它存在的负面问题。最明显的就是额外的培训开销。有过强类型语言开发经验的开发者能够一两个小时就上手 TypeScript, 但是对于只有“纯正” JavaScript (原文:vanilla JavaScript)背景的开发者可能有些费劲。
最简单的解决办法就是慢慢来。因为不需要修改原有代码就可以使用 TypeScript, 那么可以先从一个模块或开始,添加一些简单的 type declarations, 逐步扩展到继承,泛型和高级类型(intersection types, mapped types)等。我们的经验表明,使用 TypeScript 使我们受益颇多。

复盘

在 Slack, 我们致力于成为“开源良民”。我们致力于让其他开发者迁移到 TypeScript 更容易些:当我们发现哪里还没做好,我们会尝试去协助做好。
Slack 的 electron-compile 允许开发者不用担心编译的问题就使用 TypeScript 开发 Electron Apps. RxJS, 一个被 Slack Netflix Github 等广泛使用的 Reactive Extension 库,在 Slack 的支援下已经支持 TypeScript. 其他的由 Slack 桌面应用工程师开发的库都在逐步增加 TypeScript 支持(像 spawn-rx, electron-spellchecker, electron-remote, electron-notification-state, or electron-windows-notifications)。

通过官方手册 中文开始学习 TypeScript. 如果你对移植过程好奇,参考一下spawn-rx的移植。如果打算开始用 TypeScript 为 Electron app 写代码,参考electron-forge, 它实现了 Electron-compile 并支持 TypeScript 开箱即用。它甚至包含一个我们 Slack Desktop 团队最爱的一个 React/TypeScript 模板。
【-- 后记: Slack 的招人信息就不翻译了】

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容