Starting with the Problems of Large JavaScript Programs

On October 1, 2012, Microsoft publicly introduced an early preview of TypeScript, providing a language specification, compiler source code and a Visual Studio 2012 plugin. In the release announcement, Microsoft executive S. Somasegar introduced a demonstration by Anders Hejlsberg. The team was addressing a problem: JavaScript had expanded from webpage scripts to browser applications and server programs, and large projects needed clearer component interfaces and more dependable development tools.

The first public version was numbered 0.8. It allowed developers to retain their existing JavaScript code and gradually add type information; compiled programs still ran in existing JavaScript environments. The language's design had to accommodate legacy code, team collaboration and editor support rather than requiring users to rewrite an entire application first.

References: [1] [2] [6]

Types Checked During Editing and Erased Before Execution

The 0.8 specification demonstrated the approach with a very small function: writing a parameter as s: string indicated that it should be a string. Passing “hello” met the requirement, while passing an empty object produced a type-error diagnostic. When JavaScript was emitted, the parameter's type annotation was removed, and the function still ran according to JavaScript's rules. Such checking brought some errors forward to the coding stage.

Developers did not have to write a type for every variable. Given the declaration var i = 0, the compiler could infer that i had a numeric type; it could also infer the return type of a function returning a string. Editors used these results to list available members, provide parameter hints and locate symbols. Type inference complemented explicit annotations, allowing existing projects to adopt the new tools selectively.

References: [1]

Judging Interfaces by an Object's Members

TypeScript used structural type comparison. The 0.8 specification defined a Point interface requiring numeric members x and y, then had a getX function accept a Point. An ordinary object could be used in that position as long as it provided both members; providing only x did not satisfy the requirement. Classes could explicitly declare that they implemented an interface, but matching did not depend solely on a nominal declaration linking a class to an interface.

This approach suited JavaScript's practice of assembling objects as needed. The specification's jQuery example also put call signatures and object members into a single interface: the dollar-sign symbol could act as a function taking a query string and also have a get method. The type system thus described different ways of using existing programs without forcing libraries into a uniform class hierarchy.

References: [1]

Declaration Files and Module Output

Declaration files with the .d.ts extension described the types provided by existing JavaScript code without generating corresponding runtime code. The lib.d.ts supplied by default with 0.8 included interfaces for the built-in JavaScript library and the Document Object Model; separate declaration files could be written for other libraries. Teams could therefore gain call checking and autocompletion while retaining their libraries' implementations.

The module mechanism organized code and dependencies. The 0.8 compiler could emit require calls in CommonJS format, or define calls with dependency lists in Asynchronous Module Definition (AMD) format. If an import was used only to describe types, its runtime dependency could be omitted from the output. The specification treated relationships among types separately from code that actually needed to be loaded.

References: [1]

Real Projects and the Boundaries of Checking

In their 2014 paper, Bierman, Abadi and Torgersen documented practical use at Microsoft: the online editor Monaco contained about 225,000 lines of TypeScript code, and Xbox Music about 160,000. They also explained an important trade-off: to accommodate existing JavaScript idioms, type checking did not guarantee static soundness; a program could pass checking and still encounter runtime type errors.

Feldthaus and Møller at Aarhus University subsequently examined library declaration files and found 142 errors in declarations for ten libraries. In their D3 example, threshold was misspelled as theshold, leading autocompletion to suggest the wrong name while a correct call might be rejected. Declaration files expanded what tools could understand, but also created maintenance work to keep them consistent with the actual libraries.

References: [3] [4]

0.9 and 1.0 as Later Stages

Version 0.9, released on June 18, 2013, added important capabilities including generics and reorganized the compiler to improve the editing experience on large projects. Generics could relate the types of array elements, callback parameters and return values; these were extensions after the first release and should not be counted among the features already present in 0.8 in 2012.

On April 2, 2014, Microsoft announced TypeScript 1.0, offering access through Visual Studio, an npm package and source code, and began accepting community pull requests for the compiler and language services. The public preview in 2012, language extensions in 2013 and 1.0 release in 2014 constituted distinct stages of early development, each with its own concrete changes.

References: [5] [6]