Since December 2012, I have used TypeScript as my primary language while working on a large scale enterprise project due to ship next month. I want to share the details on how we are using TypeScript as a team and our workflow that has made our project a success.
Validation TypeScript enabled us to validate code usage cross-modules at compile-time. In assigning types to variables and to method arguments, we were able to effectively validate all call/get/set across every module, every build. If a property was set to type bbox.controls.Image, nothing would satisfy the compiler but an Image instance or a subclass.
Early errors We would get very detailed errors from the TypeScript compiler and with the addition of types and interfaces, the errors got even more specific.
Build process One of the first checkins and tests was to create a team build process with Ant. With a properly configured environment any developer could sync with SCM and build a working local server with all code packaged for development or production use. The build process integrates Less, RequireJS, Uglify2, TypeScript, template processing, and server generation.
In the months that followed our evaluation we settled into a team workflow with TypeScript that really benefited our project. The build process is at the center of development and our daily work. Every day looked like so:
- Update from SCM
- Run ant all ==> Full build + start local server
- Run ant dev or ant ts ==> Incremental build
- Error at build or Test in Browser
- Rinse & Repeat
The references above are also how you add in any external libraries to TypeScript. In a way definitions, interfaces, and TypeScript classes all operate in the same way. In order to simplify our build process we unified all these calls in a single init.ts file which when called by the compiler loads in all TypeScript needed by the application. Even classes that are intended to be loaded via module are denoted here so that they are externally compiled to a module file. Note the use of the export Class syntax in this external module, this tells the compiler to keep the file external as a module and a compiler flag module amd makes the compiler format modules to conform to either AMD or CommonJS format.
Over the course of development I found myself changing development strategies in terms of refactoring. I started to trust the compilers behavior to the point where I would intentionally change types, interfaces, and naming to break things in order to expose code affected. I would then correct all lines from the compiler output and refactor as needed. In many ways this has allowed me to work effectively within a larger codebase.
As for development environment, I went with Sublime Text 2 + TypeScript syntax, while the other developers on the team opted for JetBrains. I found Sublime to be a great environment for TypeScript, even without code completion, I had zero complaints. Given that the compiler can provide incremental compilation and richer ide integration I think it will be a matter of time before we see far more advanced TypeScript tooling in Sublime/Edge/Jetbrains offerings.
While I loved working with TypeScript (and will continue to do so) there is one escape hatch that every developer using it should understand. There are times when you will butt heads with the compiler and it will block your attempts to call a method or variable as typing information is unavailable. When this shows up, we found that associative array syntax would unblock the issue til we could fix thing up. Example: foo[myProperty] foo[myMethod]() would allow you to access myProperty or myMethod on foo regardless of typing information. I know it sounds odd but just keep associative array syntax in your back pocket, you will need at some point.
Some project stats on the project:
- 63 TypeScript Classes
- 12 libs ( Underscore,Require , Bootstrap , Jquery , Backbone , EaselJS )
- All Build 8 seconds
- Dev build 5 seconds
- 149Kb Libs & 411Kb Classes