We’re happy to announce the 0.8.2 preview release of TypeScript. This release has been focused on addressing key usability feedback and filling in tooling experiences. Along the way, we’ve also incorporated some of the highest-rated feature requests and bugfixes.
Being able to see API documentation comments during Intellisense and parameter help has been a highly requested feature. In fact, it’s currently the 2nd most-requested feature in the issue tracker.
With 0.8.2, the TypeScript compiler and tools now support JSDoc comments.
In the TypeScript implementation, because types are already part of the system, we allow the JSDoc type annotation to be elided, as in the example above.
You can now document a variety of language constructs (including classes, modules, interfaces, and functions) with comments that become part of the information displayed to the user. We’ve also started extending lib.d.ts, the default JS and DOM API library, with JSDoc comments.
This capability is also part of the language service, so cross-platform tools can take advantage of it.
Many of the themes in this release center around simplifying workflow. We’ve focused on a few key areas with the aim of streamlining developing in TypeScript.
Languages like TypeScript which compile to JavaScript add a build step into the development cycle. Enabling a compile-on-save mode of use minimizes this overhead by automatically updating the compiled JS when the TypeScript source changes. With 0.8.2, we’ve done work to further enable this in both the NPM-based compiler and in Visual Studio.
The 0.8.2 release adds initial support for compile-on-save in Visual Studio. Just as the name implies, when enabled the project or file being edited will be compiled when the changes are saved. For more information, please see the wiki page for compile-on-save.
TypeScript supports compile-on-save on the command line using the cross-platform NPM-based TypeScript compiler as well with the improved --watch compiler option. This option allows a compile to begin watching a set of files. Once a watched file is changed, the compiler rebuilds the corresponding output for that file.
When we talk about a type in TypeScript, we mean a collection of things that you can do with a variable (or expression). You might be able to read or write a given property, call a function, use the expression as a constructor, or index into the object. Some objects (like Date) in JavaScript can do nearly all of those! In TypeScript, interfaces are the most flexible way of describing types.
You'll see interfaces used to describe existing JavaScript APIs, create shorthand names for commonly-used types, constrain class implementations, describe array types, and more. While they don't generate any code (and thus have no runtime cost!), they are often the key point of contact between any two pieces of TypeScript code, especially when working with existing JavaScript code or built-in JavaScript objects.
The only job of an interface in TypeScript is to describe a type. While class and function deal with implementation, interface helps us keep our programs error-free by providing information about the shape of the data we work with. Because the type information is erased from a TypeScript program during compilation, we can freely add type data using interfaces without worrying about the runtime overhead.
While that sounds like a simple, one-purpose task, interfaces role in describing types becomes manifest in a large variety of ways. Let's look at some of them and how they can be used in TypeScript programs.
To define an interface in TypeScript, use the interface keyword:
interface Greetable { greet(message: string): void;}
This defines a type, Greetable, that has a member function called greet that takes a string argument. You can use this type in all the usual positions; for example in a parameter type annotation. Here we use that type annotation to get type safety on the g parameter:
function helloEnglish(g: Greetable) { g.greet('Hello there!'); // OK g.greet(42); // Not OK -- 42 is not a string g.greep('Hi'); // Not OK -- 'greep' is not a member of 'Greetable'}
When this code compiles, you won't see any mention of Greetable in the JavaScript code. Interfaces are only a compile-time construct and have no effect on the generated code.
Interfaces get to play a lot of roles in TypeScript code. We'll go into more detail on these after a quick overview.
Many JavaScript functions take a "settings object". For example, jQuery's $.ajax takes an object that can have up to several dozen members that control its behavior, but you're only likely to pass a few of those in any given instance. TypeScript interfaces allow optional properties to help you use these sorts of objects correctly.
JavaScript freely mixes members (foo.x) with indexers (foo['x']), but most programmers use one or the other as a semantic hint about what kind of access is taking place. TypeScript interfaces can be used to represent what the expected type of an indexing operation is.
Often, you'll want to make sure that a class you're writing matches some existing surface area. This is how interfaces are used in more traditional OOP languages like C# and Java, and we'll see that TypeScript interfaces behave very similarly when used in this role.
Interfaces normally describe the shape of an instance of a class, but we can also use them to describe the static shape of the class (including its constructor function). We'll cover this in a later post.
You can also use interfaces to define the shape of objects that will typically be expressed in an object literal. Here's an example:
interface ButtonSettings { text: string; size?: { width: number; height: number; }; color?: string;}function createButton(settings: ButtonSettings) { ... }
Note the use of the ? symbol after some of the names. This marks a member as being optional. This lets callers of createButton supply only the members they care about, while maintaining the constraint that the required parts of the object are present:
createButton({ text: 'Submit' }); // OKcreateButton({ text: 'Submit', size: { width: 70, height: 30 }}); // OKcreateButton({ text: 'Submit', color: 43); // Not OK: 43 isn't a stringcreateButton({ text: 'Submit', size: { width: 70 }); // Not OK: size needs a height as wellcreateButton({ color: 'Blue'}); // Not OK: 'text' member is required
You typically won't use optional members when defining interfaces that are going to be implemented by classes.
Here's another example that shows an interesting feature of types in TypeScript:
interface Point { x: number; y: number;}function getQuadrant(pt: Point) { ... }var pt = { x: 0, y: -1 };getQuadrant(pt); // OK: pt has members x and y of type number
Note that we didn't annotate pt in any way to indicate that it's of type Point. We don't need to, because type checking in TypeScript is structural: types are considered identical if they have the same surface area. Because pt has at least the same members as Point, it's suitable for use wherever a Point is expected.
Interfaces are also used to describe code that is present at runtime, but not implemented in the current TypeScript project. For example, if you open the lib.d.ts file that all TypeScript projects implicitly reference, you'll see an interface declaration for Number:
interface Number { toString(radix?: number): string; toFixed(fractionDigits?: number): string; toExponential(fractionDigits?: number): string; toPrecision(precision: number): string;}
Now if we have an expression of type Number, the compiler knows that it's valid to call toPrecision on that expression.
Moreover, interfaces in TypeScript are open, meaning you can add your own members to an interface by simply writing another interface block. If you have an external script that adds members to Date, for example, you simply need to write interface Date { /*...*/ } and declare the additional members.*
* Note: There are some known issues with the Visual Studio editor that currently prevent this scenario from working as intended. We'll be fixing this limitation in a later release.
A common pattern in JavaScript is to use an object (e.g. {}) as way to map from a set of strings to a set of values. When those values are of the same type, you can use an interface to describe that indexing into an object always produces values of a certain type (in this case, Widget).
interface WidgetMap { [name: string]: Widget;}var map: WidgetMap = {};map['gear'] = new GearWidget();var w = map['gear']; // w is inferred to type Widget
Let's extend the Greetable example above:
/** Represents an object that can be greeted */interface Greetable { /** Used to welcome someone */ greet(message: string): void; /** The preferred language of this object */ language: string;}
We can implement this interface in a class using the implements keyword:
class Person implements Greetable { language = 'English'; greet(message: string) { console.log(message); }}
Now we can use an instance of Person wherever a Greetable is expected:
var g: Greetable = new Person();
Similarly, we can take advantage of the structural typing of TypeScript to implement Greetable in an object literal:
var greeter = { greet: (message: string) => { console.log(message) }; language: 'Any';};
Starting with release 0.8.2.0, you can now update the TypeScript language services file, the compiled JavaScript that powers most of the TypeScript editor features in Visual Studio. This includes tasks like error reporting, compile-on-save, renaming, go to definition, completion lists, signature help, and others.
By updating your TypeScript language services file, you can try out the latest features we're working on before they appear in an official release. Naturally, you might encounter bugs here as the code built in the development branches isn't as stable or well-tested as the released version.
The majority of the TypeScript editor features are found in a file called typescriptSerivces.js. To update your file, you'll need to get a new copy and overwrite the existing copy.
The LKG ("Last Known Good") version of the compiler is updated somewhat frequently. You can get a copy from CodePlex using the source browser and downloading the typescriptServices.js file from the bin directory.
You'll need some basic tools first
> git clone https://git01.codeplex.com/typescript
This will set up a TypeScript repository in a subfolder of the current folder called 'typescript'.
> cd typescript > git checkout develop
If you're interested in the latest, the develop branch is probably your best bet. There may be other branches with active development; if you know of a branch you'd like to try out instead, replace develop with that branch name.
> npm install
This will install a local copy of jake, the build system we use for TypeScript.
> .\node_modules\.bin\jake local
This will produce built\local\typescriptServices.js. Copy that file as indicated below.
If you like, you can simply delete the TypeScript folder created in the first step and be done. However, if you come back at a later time and want a new fresh copy (with the latest changes), you'll need to run git pull to get the newest sources. After that, just run jake local and copy over the typeScriptServices.js file again.
You'll need to locate the folder where the TypeScript extension was installed. Look for a file called typescriptServices.js in a folder like:
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\enn4wcm5.z2b\
The highlighted portion at the end there will be different on every machine, but there shouldn't be too many of them in the Extensions folder. In some rare cases, you might have more than one subfolder that has a TypeScript installation in it; if this is the case, you'll want to use the newest one (check the Created date).
When you find the one with typescriptServices.js, backup that file and copy in the new version. After you restart Visual Studio, you'll be working with the updated services file.
We’ve recently branched for the upcoming 0.8.2 release of TypeScript. Before we talk about what’s new, we wanted to talk a bit about the engineering process that goes into making a release.
Going forward, TypeScript development will happen across three types of branches. Our current two branches of 'master' and 'develop' stay, taking the roles of stable and cutting edge development as before. We're also going to be adding branches for each of the upcoming releases, so that they each release can stabilize. The current 0.8.2 release is wrapping up, and you can watch the stabilization process by going to the CodePlex repo and selecting "release-0.8.2" in the dropdown. For more information, there's also a wiki page with more details about the separate branches.
We’re currently working on the 0.8.x release train, which is focused on addressing key usability feedback and filling in tools experience. In parallel, design work on the upcoming 0.9.x release train is underway, in which we expect to address some of the larger TypeScript language changes that are under discussion on the TypeScript forums and issue tracker. More details on early 0.9.x design thinking coming in a future post.
The 0.8.2 release will include, among other features and bug fixes, these popular requests:
As always, you can follow the work on CodePlex, and share any feedback on the forums and issue tracker.