我用 TypeScript 语言的七个月
从 2012 年 12 月开始,我用 TypeScript 作为主要语言,用于一个大规模的企业项目。项目下个月要发布了,我想分享一些细节内容,包括我们团队怎么使用 TypeScript 的,还有成就项目的工作流程。 什么是 TypeScriptTypeScript 是由微软开发的一个能够在 Node.js 上运行的开源语言和编译器。这个语言是在 ECMAScript6 基础上演化并吸收了生成 Javascript 类别和接口的一些特性。Typescript 的编译器使用 TypeScript 语言编写,并且能够在任何兼容 Javascript 的程序内运行,同时它也是作为 node.js 的一个工具包发布的。所以该语言最终生成的仍然是 Javascript 脚本。 评估在 2012 年十一月期间,我们发现我们所选择的开发工具和对于 Typescript 的试用确实给团队带来很多便利。起初,我们试用了 Haxe,Dart,Coffescript 等一系列语言,但是我们最终还是被拥有 ECMAScript6 特性 Javascript 编译 器:Tyepscript 打动了。我们所期望的是使用 Javascript 作为开发语言但同时又想要在我们的开发过程中注入一定的结构框架,而且希望能够依靠编辑器来进行一些纠错和验证。所以实际上我们最终还是只有在 Javascript 和 Typescript 之间作选择。在这基础上,团队作了几个小型的项目雏形,并且迅速发现了以下一些有趣的特性: 验证:Typescript 能够在编译的同时让我们验证一些代码在不同模块中的重复使用。在声明变量类型和定义语句方法的时候,我们能够很有效的对所有 call/get/set 的使用在所有模块中进行交叉验证。如果一个属性被赋给了 bbox.controls.image 类,那么在编译时只有图片实例或其子类才能够满足编译条件。 报错:Typescript 编译器能够提供非常细节的报错,如果提供额外的类和接口信息,那报错的内容会更加的详细。 轻量化:Typescript 的类和接口在编译时会蒸发的一干二净从而生成纯净的 Javascript 脚本。 ECMAS6(ES6):Typescript 在 ES6 的基础上添加了类和接口。它让我们能够利用最新的 Javascript 语法规则去编写程序同时在编译时添加 ES3,ES5 的标签,使得其能够兼容 ES3,ES5 的标准。这让代码的整理变得非常轻松。 Build process:在我们最初的检验和测试过程中,有一个部分是利用 Ant 创建一个团队进程。通过对环境的适当调试,开发者能够和 SCM(架构部署)进行同步并且建立一个拥有所有代码组件(codepakages)的本地服务器用于开发和调试。整个创建 的过程迁入了 LESS,RequireJS,Uglify2,TypeScript 模板处理和服务器的生成。 使用在评估之后的几个月里,我们基于 TypeScript 建立了一个稳定的团队工作流程并且从中获利良多。进程的创建(buildprocess)是我们开发过程中一个至关重要并且每天都会使用到的一个过程。基于 TypeScript,我们每天的工作流程基本上如下所述:
我个人非常喜欢这样的运作模型,从中我发现我们花在浏览器测试阶段的时间远少于之前的 JavaScript 项目。由于 Build 过程中就已经检校了一些接口/类型/语法的错误,因此在浏览器测试阶段我们就减少了对此类错误的勘误工作量。一旦所有人都熟悉了 TypeScript 的 debugging 流程,我们大大的提高了工作效率,这是在以前的开发过程中所没有体验过的。花了 5 秒钟编译但是最终却删除了整一个没有运作的毫无意义类听起来有点不能接受。这种防患于未然的 debugging 方式节省我们大约 2 个月的时间,而且代码的质量也大大提高了。 当初在我们进行开发的时候,TypeScript 定义文件的质量和内容不是非常理想。定义文件能够让你非常安全的从外部定义 JavaScript 的接口类型,但这样做你的代码必须在编译时完全遵照定义文件。自从这个项目开始之际,我们借 DefinitelyTyped 项目为一些主要的或者非主要的 JavaScript 库编写润饰了 180 个定义。小组最后在创建进程时使用了关于 Require,JQuery,Backbone,Bootstrap,Underscore 和 EaselJS 的定义文件。现在为TypeScript添加定义文件,你只要在你的 main.ts 文件中添加一下的代码就可以了。 根据同样的方法你也可以向 TypeScript 中添加一些外部库。某种程度上来说定义文件,接口和 TypeScript 的类的运作方式是类似的。为了简化我们创建进程的过程,我们将这些调用过程全部综合到一个 init.ts 文件中,这样当编译器工作的时候就可以自动载入所有该应用所需要 TypeScript 代码。哪怕是那些本需要通过先调用模块才能调用的类也能在这里被调用表达,这样这些类就会在编译时预先在外部生成一个模块文件以供使用。注意这个外部模块的代码中”exportClass”的语法,它会告诉编译器将文件视为一个外部模块进行调用,而编译器标识 ”-moduleamd” 会使得编译器将模块编排成 AMD 或者 CommonJS 的格式 除此之外,TypeScript 还有另外一个很优雅整合代码的功能。每一个类和变量都被输出到浏览器窗口实体之外的一个路径里以供全局访问。我们使用了 bbox 作为所有类和变量的命名空间,同时提供了输入时的支持,你也可以便捷的为你自己的应用建立一个良好命名空间。以上的模块包含在 了”bbox.controls”里并且在运行时可以发现它被输出到了 bbox.controls,Bounds 中。考虑到我们有用到大约 60 多个类,我们最大化的使用了这个模块系统并且在开发过程中使用的非常顺利。你可以遵照这个方法自由的导出和类别化你自己的变量或者所有的类,而不需要让所有的变量都归属于某个类。由于提供了类别和权限的限制,类别化输出的变量对于模块内单一的变量非常适用。随着类别和模块的介入,你使用 JavaScript 的方式也会有所改变,并且很难形成比较差的实践方式。随着一个能够监测到通过数组或者一个很特殊的类别重写了某实体的高级编译器,你可以一不同的方式利用 JavaScript 进行开发,TypeScript 作为一种语言有着它独特的工作模式。它已经不完全是 JavaScript 了,但全包含了 JavaScript 原有的所有特性。 通过一系列的开发实践我发祥我自己已经通过对代码的重构实现了开发策略的转换。由于有时需检查在不同部分受到修改影响的代码,我开始在有意识的改变变量类别,接口和命名空间等方面相信编译器本身的行为。在编译之后我才会修改结果,并且根据需要进行代码的重构。这在很多方面都使我能够很有效处理较大的代码量。编译器为我省去了很多 debugging 的负担。 至于我的开发环境,尽管其他团对成员选择了 Jetbrians,我依然选择了 sublimetext2+TypeScirpt 语法高亮。毫无异议, 我发觉即使没有自动完成的功能,sublime 依然能提供很好的 TypeScript 开发环境。由于 TypeScript 编译器本身就有着增量式的编译功能和丰富的 IDE 整合功能,可能需要更多的时间来证明到底 Sublime/Edge/Jetbrains 哪一个才是最适合的开发工具。 最后,当我爱上使用 TypeScript 的同时(当然,我也会继续用下去),我发现了一个令人望而生畏的地方。有很多次,当你一头扎进编译环境中,编译器却由于输入信息不可用而阻止你调用一个方法或者变量。每当这时,我们发现只有我们手动修复 bug 时,利用关联数组语法 (associativearraysyntax)去解决这个问题。比如:无论什么样的分类形 式,foo[‘myProperty’]foo[‘myMethod’]() 应该能够让你介入 foo 的 myProperty 和 myMethod 属性。这看起来有一些不可思议,但只要记住随时可能用到关联数组语法 (associativearraysyntax)就万事大吉了,你总有需要它的地方。 最后附上一些项目开发过程中的总结数据:
总结在过去 7 个月里用 TypeScript 做开发是一件非常愉快的事情。在之前的开发经验里,我使用过 ActionScript/ES4,但由于有着相似的结构,我很快就适应了 TypeScript,同时保持了 JavaScript 优雅的代码便捷性。在很多方面,我发现对于 TypeScript 的使用,的确使我们在团队代码质量和截止日期上有了很大提升。我不认为我是微软的死忠,但是 TypeScript 确实使我眼前一亮。它是过去三年里我所接触的最好的也是比较容易接受的一个网页开发的工具。我期待在未来能够在更多的项目中用到, 并且能够参与到该语言/编译器的开发中去。 这周我将会在旧金山的 Build 去了解 TypeScript0.9 的一些特性,下个月我会在 Senchacon 和360Stack。 我爱 TypeScript! 来自:http://blog.jobbole.com/43675/ ![]() |