Last week was the 5th anniversary of the launch of TypeScript, and I had the opportunity to go back to visit Anders and the team for the weekly TypeScript design meeting — to congratulate them on the milestone and on the incredible progress they’ve continued to make with TypeScript over the 4 years since I left the team.
I also took the opportunity to dig up some old demos I had done of TypeScript from the earliest days of our work on TypeScript (then codenamed Strada) to share with the team.
I started working on a project to help application-scale development teams manage large JavaScript codebases in the Fall of 2010 along with Steve Lucco. Steve had been talking to a few engineering VPs in Office who highlighted the rapid transition of their development teams from C++/C# over to JavaScript as they invested in web-based applications and experiences. These teams missed the productivity tools and confidence that the type systems of C++ and C# and the Visual Studio IDE had provided — and they wanted to know what we could do to help as they moved to JavaScript. At the same time we saw the broader industry trend in a similar direction as fast JavaScript engines, progress on HTML5, and several impressive large web “applications” had all converged to quickly change the way JavaScript was being used on the web over the previous couple of years.
There were many options already available, but none seemed to be resonating well with a broad enough section of the market. Internally at Microsoft, Script# was being used by some large teams. It let them use C# directly instead of JavaScript, but as a result, suffered from the kind of impedance mismatch you get when trying to stand at arms length from the runtime model you are really programming against. And there was Google’s Closure Compiler, which offered a rich type system embedded in comments inside JavaScript code to guide some advanced minification processes (and along the way, caught and reported type-related errors). And finally, this was the timeframe of a rapid ascendancy of CoffeeScript within the JavaScript ecosystem — becoming the first heavily used transpiled-to-JavaScript language and paving the way for transpilers in the JavaScript development workflow. (Aside — I often explained TypeScript in the early days using an analogy “CoffeeScript : TypeScript :: Ruby : C#/Java/C++”, often adding — “and there are 50x more C#/Java/C++ developers than Ruby developers :-)”)
What we quickly discovered we wanted to offer was a “best of all worlds” at the intersection of these three — a language as close as possible to JavaScript semantics (like CoffeeScript) and syntax (like Closure Compiler) but able to offer typechecking and rich tooling (like Script#).
We started working on it as a side-project in the Fall and Winter of 2010. As a forcing function to help ensure we had something to show, we signed up to do a presentation internally on what we were working on at a mini-conference with programming languages folks from both research and product teams across Microsoft. However, in the month before the talk, Steve (the only engineer on the project at the time!) had a wrist injury which prevented him from doing any serious coding. So, not wanting to back out of the talk — I decided to hack something together that would allow us to get across the experience we were trying to deliver — even without having an actually working compiler. (Steve did shortly after build the first real TypeScript compiler, which enabled our first internal customer — the team that was building what would later become VS Code — to start using TypeScript for real).
Here’s the main piece of code we used in the first Strada demo outside our immediate team — on February 1st, 2011.
There are a number of elements of what ultimately became TypeScript that stand out here.
extern
to be able to seamlessly interoperate with plain-old-JavaScript code and libraries — even when they didn’t (yet) have types associated with them.But there are also several things you can see here that we ultimately moved away from with TypeScript.
string name
instead of name: string
as they are now in TypeScript. We initially gravitated to that syntax because we used the name var
for the type that is now called any
, allowing the implicit typing to any
to be effectively explicit in a statement like var x = ...
. This was also similar to the work done not long before in C# when var
was introduced there. But putting a type in this position in the grammar leads to a number of parsing issues, and there was good precedent for JavaScript-like languages which used the name: string
format (most notably — ActionScript and the defunct ECMAScript4). This one changed over quite early — code samples I have from just a couple months later already use the :
syntax.class Foo : Bar
syntax for super classes — which we later transitioned over to use extends
.<script type="text/strada">
block — and the comment noting that StradaCompiler.js
is responsible for compiling text/strada
blocks on the fly. We actually imagined at the time that you would provide TypeScript code directly in your HTML via <script>
tags — instead of having a separate build step — and it would get transpiled on page-load (and hopefully cached). This was a somewhat popular technique for small-scale CoffeeScript projects at the time, but as we talked to more larger development teams we found this was not practical for many/most production workflows. In practice, getting this kind of tight development workflow experience ended up being solved by tools like WebPack and similar running watchers that dynamically recompile code but still present it to the browser in a compiled form.But even more fun is how we made that piece of code actually work.
I had a little side project at the time to write a JavaScript interpreter in F# (as a cathartic tool in my transition from working on F# to working on JavaScript), and part of that was a fairly solid JavaScript (ES5) parser. I made some (surprisingly minor) modifications to the grammar to support the new constructs we were adding with Strada — mostly along the lines of this:
I hacked into the pretty-printer a way to emit the resulting ASTs as plain JavaScipt — but instead of throwing away the types, I converted them into into Closure Compiler comments. Now, there’s more or less no way to make this a robust process — but it was enough for the demo!
From there — you guessed it — we just invoked the Closure Compiler on the resulting code as a “type checker”. Closure Compiler had (and still has) a convenient hosted service on AppEngine, so we just POSTed the pretty-printed code to that service to get errors.
These were also the days of Silverlight (and Flash) still playing a meaningful role on the client side. And so to run the parser (implemented in F#), we hosted it as Silverlight inside the page — which reached out to find text/strada
scripts, parse them, send them to Closure and report the errors.
The result was that we could get live error reporting as we changed the contents of the <script>
tag inside the developer tools, giving the impression that there was just a background typechecker running. This managed to demo some key parts of the experience we were trying to enable — even though in practice the way were were showing it couldn’t possibly scale to even a single real user 😄.
Here’s one more of the code snippets we demoed. You can see a few more interesting differences from what became TypeScript here — double
as a type instead of number
(we imagined we might add int
as well — but that took us away from JavaScript semantics) and the I
prefix on interfaces as a C#-inspired convention — along with some things that stayed, like interfaces and the ability to seamlessly mix untyped object lookups with strongly typed classes.
A little over a year and a half after that first demo, we launched TypeScript. And in the 5 years since, TypeScript has become one of the fastest growing programming languages across the software industry.
Watching now from the outside, I’m constantly impressed with the TypeScript team’s ability to both stay true to it’s roots of being a thin layer on top of JavaScript, while at the same time evolving to meet the challenges of being a typesystem that can in practice be productively used across almost any JavaScript codebase. As new frameworks and development styles have emerged in the JavaScript ecosystem, TypeScript has managed to evolve as well, while still staying focused and approachable.
Congrats to everyone on the team and in the TypeScript community for the incredible work making this happen!
Our JSConf EU 2012 presentation launching TypeScript