Most recently, the TypeScript
fifth anniversary took place, and I had the opportunity to see
Anders and the development team at the weekly technical meeting. I wanted to congratulate them on the important milestone in TypeScript, to tell them how much they have done in the four years that have passed since my departure from the project.

In addition, I tracked down some old demos made on TypeScript at the very beginning of the project (then called Strada), in order to view them along with those who are working on TypeScript now.
')
Today I want to talk about how TypeScript began.
Start
In the fall of 2010, we started working on a new project with Steve Lukko. His goal was to help application development teams manage large amounts of JavaScript code. Steve spoke to several technical directors in the main office. They told about the rapid transition of their departments from C ++ / C # to JavaScript, that now serious forces are being invested in the development of web applications and corresponding scripts of interaction with programs. The development teams lacked quality tools, such as Visual Studio, and the amenities provided by the C ++ and C # type systems. They would like to know what we can do to make the transition to JavaScript easier. At the same time, we noticed a powerful IT trend going in a similar direction.
Quick JavaScript engines came out, HTML5 developed, several impressive web application sizes and features appeared. All of this together indicated a rapid change in how JavaScript is used on the web; it was no longer something like, say, in the previous couple of years.
By that time there were already many solutions to the above problem, but none of them suited us, did not meet the expectations of a fairly wide market niche. Inside Microsoft, some big teams used
Script # . This allowed them to use C # instead of JavaScript. However, as a result, they were too far away from the environment for which they were, in fact, programmed. This caused some inconvenience. There was also the
Google Closure Compiler , which offered a rich type system embedded in comments inside the JS code, which allowed you to manage some advanced minification processes (and, at the same time, track errors related to types and report them). And finally, there was the heyday of
CoffeeScript . CoffeeScript was the first widely used JavaScript-translatable language that paved the way for transpilers in JS development. By the way, at the very beginning, I often talked about the features of TypeScript using the following analogy: “
CoffeeScript: TypeScript :: Ruby: C # / Java / C ++ ”, often adding: “
there are 50 times more C # / Java / C ++ developers than those who write in Ruby :) ".
We quickly realized that we would like to create something located at the intersection of the three aforementioned technologies, something that could become in all respects better than what already happened. In our view, this was supposed to be a language whose semantics and syntax are as close as possible to JavaScript. These properties, respectively, possessed CoffeeScript and Closure Compiler. Further, we wanted this language to support type checking and convenient tools, that is, that it takes all the best from Script #.
We began work on TypeScript as a minor project in the autumn and winter of 2010. In order not to relax, so that the results of our work can be shown to others, what motivates, we have planned an internal presentation with a demonstration of what we have done. This was supposed to be a mini-conference, to which employees from the research group and the software development group at Microsoft were invited. However, a month before the event, Steve (the only engineer in the team at the time) injured his wrist, which prevented him from programming normally. In the end, not wanting to shy away from the planned performance, I decided to put together everything that would allow us to demonstrate what we are striving for, even without having a really working compiler. (Soon, Steve made the first true TypeScript compiler, which allowed our first internal users - the team that created what later became VS Code - to start using TypeScript to solve real-world problems).
First demonstration
Here is the main code snippet that we used in the Strada demonstration outside our small team on February 1, 2011.
<!DOCTYPE html> <html> <meta http-equiv="X-UA-Compatible" content="IE=9"> <head> <title>JavascriptWebClient</title> <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.js" type="text/javascript"></script> </head> <body> <h1>Employee Pay</h1> <h3><font color="#3AC1EF">â–ŤSalesEmployee's are paid: <span id='salesEmployeePay'></span></font></h3> <div id='results'></div> <script type='text/strada'> extern var $; class Employee(string name, double basepay) { public double calculatePay() { return basepay; } } class SalesEmployee(string name, double basepay, double salesbonus) : Employee(name, basepay) { public string getName() { return name; } public double calculatePay() { return base.calculatePay() + salesbonus; } } var employee = new Employee('Bob', 1000); var salesEmployee = new SalesEmployee('Jim', 800, 400); $('#salesEmployeePay').html(salesEmployee.calculatePay()); </script> <script src='StradaCompiler.js' type="text/javascript"></script> </body> </html>
Here there are many elements that eventually entered into the language, which is now called TypeScript.
- The implicit process of applying types in lines 28-30 without the need for annotation.
- Classes - as a way to describe the implementation of the mechanisms of the application and the types of variables. Classes are convenient in simple JavaScript, but in TypeScript they play a more important role, allowing, in one go, to describe both the implementation and the type without the need to perform double work.
- The
extern
keyword that allows you to interact transparently with regular JS code and libraries — even if they are not provided (or not yet provided) with information about types.
However, here you can see something that eventually we removed from TypeScript.
- Class syntax We really wanted to use the more “functional” class syntax shown here. I, shortly before, worked on F #, which uses a similar short syntax for classes. In addition, we then discussed similar syntax for C #. It should be noted that this syntax was well suited to the then-popular style of using closures to represent states in JavaScript “classes” - instead of object properties, as can be seen in an approach based on class prototypes that were just standardized in ECMAScript. This topic was controversial almost until TypeScript release.
What happened to classes in ECMAScript went in a different direction, and although we wanted to bring TypeScript closer to future standards, we did not like the fact that we would have to write TypeScript classes on top of standard constructions (in normal situations this would lead to a fourfold repetition of the name variable). As a result, we have brought standards to the fore. Then it was risky. The fact is that it was not quite clear what fate awaits ES6. Maybe he, like ES4, would never have come out. However, for us the main thing was to follow the main goal of TypeScript, which was supposed to be as light as possible abstraction over JavaScript, even taking into account that JS, in its development, passed from ES3 to ES5, then - to ECMAScript2017 and will develop further .
- Specifying types as prefixes. In the above code, you can see something like a
string name
instead of a name: string
- a record that is used in modern TypeScript. At first, we tended toward this syntax, since we used the var
keyword for the type that is now called any
. This allows implicit casting to the any
type to be explicit in expressions like var x = …
It was also, moreover, similar to what was recently done in C #, when the implicit type var
appeared there. But the grammar of the language, which involves placing information about a type in a given position, leads to many problems with parsing. In addition, there was a valuable precedent in this area with languages ​​like JavaScript, which used the name: string
format (in the first place, it was ActionScript and it did not come out ECMAScript4). As a result, we changed the approach used here very early. In the code samples that I had two months after the first presentation, the syntax with a colon was already used.
- Superclasses. We had a
class Foo : Bar
for superclasses, in the style of C #. Later we switched to the keyword extends
.
- The approach to compiling scripts. Here's another little thing. Notice that the code is located in the
<script type="text/strada">
block, and the commentary indicates that StradaCompiler.js
is responsible for compiling text/strada
blocks, which is called "on the fly". We then imagined that TypeScript would be placed directly in HTML using <script>
tags, instead of using a standalone project build phase, and this embedded code would be transported (and hopefully cached) when the page loads. At that time, this approach was popular in small CoffeeScript projects, but after discussing this with large enough development teams, we found that this is not practical for many, if not most, real-world situations. In practice, such difficulties, ultimately, were solved using tools like WebPack, which dynamically recompiled the code, but presented it to the browser in a compiled form.
I must say that all this - more flowers. Much more interesting was how we made this piece of code work.
How it worked
I then had a small minor project on writing a JavaScript interpreter on F # (something like a means to move from working on F # to working on JavaScript). Part of this project was a fairly stable JavaScript (ES5) parser. I made some modifications to the grammar (it took them a little surprisingly) to support the new constructs that we added to Strada. Basically it looked like this:
@@ -459,8 +466,12 @@ StatementList: | Statement { [$1]} // See 12.2 VariableStatement: - | VAR VariableDeclarationList SEMICOLON { VariableStatement(List.rev($2)) } - | VAR VariableDeclarationList { VariableStatement(List.rev($2)) } + | Type VariableDeclarationList SEMICOLON { VariableStatement([], false, $1,List.rev($2)) } + | Type VariableDeclarationList { VariableStatement([], false, $1, List.rev($2)) } + | READONLY Type VariableDeclarationList SEMICOLON { VariableStatement([], true, $2,List.rev($3)) } + | READONLY Type VariableDeclarationList { VariableStatement([], true, $2, List.rev($3)) } // See 12.2 VariableDeclarationList: | VariableDeclaration { [$1]}
By the way, it seems that in this early version we had
readonly
.
I found a way to output the resultant ASTs like regular JavaScript, but instead of discarding types, I converted them into Closure Compiler comments. As a result, the design was not very stable, but that was enough to launch the demo!
After that, which is quite logical, we simply called Closure Compiler for the resulting code as a type checking tool. Closure Compiler had (and
still has ) a convenient service on AppEngine, as a result, we simply sent our code as a POST request to this service and received information about errors.
In those days, Silverlight (and Flash) still played a prominent role in the development of client applications. And so in order to run the parser (written in F #), we placed it on the page as a Silverlight application, which found
text/strada
scripts, parsed them, sent them to Closure, and reported errors.
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; using System.ServiceModel.Activation; using System.Net; using System.IO; using System.Web; namespace JavascriptWebClient.Web { // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ClosureCompile" in code, svc and config file together. [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] [ServiceBehavior(IncludeExceptionDetailInFaults=true)] public class ClosureCompile : IClosureCompile { public string DoWork(string srcText) { System.Diagnostics.Debug.WriteLine("Hello!"); var request = WebRequest.Create("http://closure-compiler.appspot.com/compile"); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; var stream = request.GetRequestStream(); // Send the post variables StreamWriter writer = new StreamWriter(stream); writer.Write("output_format=xml"); writer.Write("&output_info=compiled_code"); writer.Write("&output_info=warnings"); writer.Write("&output_info=errors"); writer.Write("&output_info=statistics"); writer.Write("&compilation_level=ADVANCED_OPTIMIZATIONS"); writer.Write("&warning_level=verbose"); writer.Write("&js_code=" + HttpUtility.UrlEncode(srcText)); writer.Flush(); writer.Close(); var response = request.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader reader = new StreamReader(responseStream); // get the result text string result = reader.ReadToEnd(); return result; } } }
How many memories does this code cause ...
As a result, we could get interactive error information when the contents of the
<script>
tag were changed using developer tools, which gave the impression that the background type checking system is working here. This allowed us to demonstrate some key features that we wanted to achieve. True, the way it was done was not even suitable for at least one real programmer to work on the project.
Here is another piece of code that we then showed. Here you can see some more interesting differences from what turned into TypeScript as a result. For example, the type is
double
instead of
number
(we thought about adding
int
, but this led us away from JavaScript semantics), and the prefix
I
for interfaces, as is customary in C #. There are also some things that remain, such as interfaces and the ability to freely mix the search for elements in untyped objects and strongly typed classes.
interface IHashtable { double lookup(string i); void set(string i, double d); } class Hashtable() { var o = {}; public double lookup(string i) { return this.o[i]; } public void set(string i, double d) { this.o[i] = d; } } interface IExpression { double evaluate(IHashtable vars); } class Constant(double value) : IExpression { public double evaluate(IHashtable vars) { return value; } } class VariableReference(string name) : IExpression { public double evaluate(IHashtable vars) { var value = vars.lookup(name); return value; } } class Operation(IExpression left, string op, IExpression right) : IExpression { public double evaluate(IHashtable vars) { double x = this.left.evaluate(vars); double y = this.right.evaluate(vars); switch (this.op) { case '+': return x + y; case '-': return x - y; case '*': return x * y; case '/': return x / y; } } } IExpression e = new Operation(new VariableReference("x"),'+',new Constant(3)); function f() { IExpression e = new Operation( new VariableReference("x"), '*', new Operation( new VariableReference("y"), '+', new Constant(2) )); IHashtable vars = new Hashtable(); vars.set("x", 3); vars.set("y", 5); e.evaluate(vars); // Outputs "21" vars.set("x", 1.5); vars.set("y", 9); return e.evaluate(vars); // Outputs "16.5" } f();
Results
About a year and a half after the first demonstration, we
released TypeScript . And, after 5 years, TypeScript has become
one of the fastest growing programming languages ​​in the software development industry.
Now, looking at it as an outsider, I cannot help but admire the consistency with which the TypeScript team adheres to the original ideas on which the language is built. The idea is that TypeScript is just a lightweight abstraction over JavaScript. It creates a pleasant impression and how the language develops, keeping in all the same, originally designated framework. Namely, its purpose is to provide a type system that can be used productively in almost any JavaScript projects. TypeScript remained true to its ideals with the advent of new frameworks and development styles in the JS ecosystem.
Congratulations on the anniversary TypeScript. I thank the development team and the TS community, thanks to which TypeScript is what it is for amazing work.
Dear readers! Do you use typeScript?