What I learnt from using TypeScript “for real”
- TypeScript is awesome, for sure, but there needs to be improvements to tooling to streamline the experience.
- TypeScript is strongly typed of course, but it doesn’t force you to code in this manner, which can result in shoddy code.
- Tweaking is required to make bundling work properly.
When I started the project, I was using Visual Studio 2012 Update 4 with TypeScript 1.0 pre-installed. I was brought in to work on this project on a short term basis, and this is how the machine was set up when I arrived. Normally I wouldn’t choose to use Visual Studio 2012 (I like to use the latest tools where possible) but I decided to just go with it and make do. Once deficiencies in tooling became clear, I did eventually push for an update to Visual Studio 2013 Update 4, which in fairness resolved most of my frustrations.
I have a license for JetBrains ReSharper, which has support for TypeScript 1.4 (and indeed that is the default setting when using ReSharper 9). This was actually my first tooling problem.
When using Visual Studio 2012, you are using TypeScript 1.0 (unless you have proactively updated to version 1.4). Naturally 1.0 is an older version and doesn’t support language features such as protected methods or ECMAScript 6 template strings. ReSharper, however, does understand these features and offers suggestions to use them. Trying to use these features results in build errors, which of course was confusing because I didn’t understand that I was actually using version 1.0 at the time (does it say anywhere? not to my knowledge).
Bundling in MVC
The project I was working on used some features of ASP .NET and Web API. One such feature was bundling and minification, which I always use to improve performance and reduce server load. I wrote many based files and interfaces as you would expect, as both are fully supported in TypeScript. However, what I later realised (perhaps I should have realised at the start, but hey) was that order is important. The MVC bundler doesn’t care about order, so there’s a big problem here. After switching on bundling, I went from 0 runtime errors to at least 20. There are two approaches I could have taken to resolve the problem;
- Create two separate bundles, one for base classes, the other for derived classes (I don’t care for this)
- Create a custom orderer and use naming conventions (prefix base class files with the name “Base”) to ensure order.
TypeScript is inconsistent
I love the strongly typed nature of TypeScript, that’s the feature that appeals most to me. I do however have the following qualms;
TypeScript does not force you to use the language features of TypeScript
What I mean is this, I can create a local variable and assign it a type of Element;
var element : Element = angular.element('.myelement')
The type constraint is redundant, and ReSharper makes a song and dance about the fact and basically forces you to get rid of it (yeah, I know I could turn this off but at the end of the day ReSharper is right). I can assign function parameters type declarations, but I don’t have to. (I did eventually go back in fill these in where I could). I know that I should use type declarations and to be honest I wish I did use this feature more, but I’m lazy. Next time I’ll be sure to do this from the start as I think it adds further structure to the code.
TypeScript doesn’t know it all
The project I was developing was built in conjunction with AngularJS. I’ve had an up-down relationship with AngularJS to say the least, but I decided to fully embrace it this time and not switch between jQuery and Angular (yeah I’m aware that Angular uses jQuery lite under the hood, I’m referring to not switching between using
angular.element()). I made heavy use of Angular Scope and I often had a dozen or more child scopes running on any one page. So as a result, I had lots of code that looked roughly like this;
var scope = angular.element('.myselector').first().children('.mychildren').scope()
var children = angular.element('.myselector').first().children('.mychildren'); var scope = children.scope();
Ok its not a big deal. The scope variable is now of type
any, so there’s no IntelliSense and no compile time checking. But hey, wait, isn’t that the main point of using TypeScript in the first place? Now if I pass scope to another function, I’ll exacerbate the problem (due to the fact that the parameter will have to be of type