来自Lyft的前端工程师Mohsen Azimi介绍了Lyft向TypeScript转型的过程,说明JavaScript类型系统的重要性、为什么Lyft选择TypeScript以及他们的一些实践经验。以下内容翻译自作者的博客,查看原文TypeScript at Lyft。
在我刚刚成为JavaScript开发者的时候,当有人说要给JavaScript加入类型系统,我就会问自己:为什么要这么做?
现在,我已经成为一个JavaScript老手,我难以想象没有类型系统支持的JavaScript会是怎样的。大型的JavaScript应用需要类型信息来提升扩展性和可维护性,Lyft的很多JavaScript项目(从Lyft.com网站到我们的内部工具)也不例外。当我还是个JavaScript狂热者的时候,看着Lyft的团队和代码库在膨胀,开始意识到存粹的JavaScript已经无法支撑起大型的应用了。
但这也并非意味着要扔掉JavaScript。如果能够加入类型系统,一切都会变得不一样。类型系统可以减少bug,开发者也因此能够更加方便地查看代码。下面我将讲述Lyft为什么选择了TypeScript以及是怎么做到的。
Bug!
“Uncaught TypeError: Cannot read property "foo" of undefined”是JavaScript最常见的一个错误。在访问一个未定义(undefined)的引用对象的属性时就会发生这个错误。Lyft的纯JavaScript项目在生产环境经常会出现这个问题。JavaScript的常见错误还包括拼写错误,比如“document.getElementbyId”,这类错误在生产环境会引发大问题。
REST API的类型不匹配问题虽然不常见,但一旦发生就是个大bug。比如,API响应消息里的一个字段从数字类型变成字符串类型,会导致JavaScript出现不可预期的行为。
开发效率
浏览大型的JavaScript代码库不仅耗时而且容易让人感到困惑,找不到函数的定义或搞不清楚函数可以接收哪些参数都是常有的事。以下列这段代码为例:
/** * Create an input element * @param {string} type * @param {string|boolean} value * @return {HTMLInputElement} */ function createInput(type, value) { const el = document.createElement('input'); el.type = type; if (type === 'checkbox') { el.checked = value; } else { el.value = value; } return el; }这个函数根据传入的类型返回一个HTMLInputElement对象,如果是复选框类型,就把复选框的“checked”属性值设置为传入的值,否则的话就创建一个输入框,并把输入框的值设置为传入的值。
这里可能会出现bug,假设在创建复选框时传入了错误的值,比如:
const input = createInput('checkbox', 'false')即使代码注释里写得很清楚,仍然无法阻止bug的产生。把字符串“false”赋值给复选框,但复选框的状态仍然会是“true”,因为字符串“false”会被解析成布尔类型的“true”。
而如果有了类型系统,就可以通过重载帮助开发人员写出正确的代码:
/** * Create an input element */ function createInput(type: 'text', value: string): HTMLInputElement; function createInput(type: 'checkbox', value: boolean): HTMLInputElement; function createInput(type, value) { // code }类型系统让代码变得更强大,通过API级别的语义可以在一开始就把bug扼杀在襁褓里。
类型系统让重构变得更简单,开发人员也因此可以放心地做出代码变更。例如,当一个函数签名发生变化,在调用方代码没有做出相应改动之前是无法通过TypeScript编译的。
强类型的代码之所以更容易进行重构,是因为类型检查器可以确保代码变更可以与项目的其他部分兼容。IDE或代码编辑器为类型系统提供了支持。
带有类型信息的模块更容易维护。使用TypeScript开发的模块在一些编辑器里可以显示出API的提示信息。
TypeScript与FlowType的对决
我们有多种JavaScript类型系统可选择:
带有JSDoc类型注解的Google Closure编译器
FlowType
TypeScript
虽然我们最终选择了TypeScript,但做出这个决定也并不是那么容易的。我们的团队分成两个阵营,一个倾向于选择FlowType,一个倾向于选择TypeScript。
“FlowType就是JavaScript”
FlowType被认为“就是JavaScript”或者“带有类型注解的JavaScript”。这种看法有失偏颇。FlowType是一门独立的语言,它的语法是JavaScript的超集。它使用了.js作为文件扩展名,所以导致了人们的混淆。实际上,不管是JSX还是FlowType,它们都不是JavaScript。同样,TypeScript和ECMAScript也不是。
调用方类型检查
调用方类型检查是FlowType的一个非常受欢迎的特性。比如:
function power2(a) { return a * a; } power2('string')