Today, we’re happy to announce the release of TypeScript 1.6. This release adds support for React/JSX, class expressions, and a rich set of new capabilities in the type system. It also provides stricter type checking for object literals.
You can download TypeScript 1.6 for Visual Studio 2015, Visual Studio 2013, on npm, or as source.
React/JSX
Designed with feedback from React experts and the React team, we’ve built full-featured support for React typing and the JSX support in React. Below, you can see TypeScript code happily coexisting with JSX syntax within a single file with the new .tsx extension. This allows React developers to intermingle HTML-like syntax with TypeScript code.
Our goal was to make it feel natural to work with React/JSX and to have all the type-checking and autocomplete capabilities of TypeScript. This allows you a rich editing experience for working with React and JSX when using VS, VS Code, and Sublime.
Class expressions
This release also makes it possible to write class expressions, as we continue to round out the ES6 support in TypeScript. Similar to class declarations, class expressions allow you to create new classes. Unlike class declarations, you can use class expressions wherever you use an expression. For example, you can now create a class and use it in your extends clause.
class StateHandler extends class { reset() { return true; } } { constructor() { super(); } }
var g = new StateHandler(); g.reset();
This class can be anonymous and still has all the same capabilities of class declarations.
User defined type guards
In earlier versions of TypeScript, you could use if statements to narrow the type. For example, you could use:
if (typeof x === “number”) { … }
This helped type information flow into common ways of working with types at runtime (inspired by some of the other projects doing typechecking of JS). While this approach is powerful, we wanted to push it a bit further. In 1.6, you can now create your own type guard functions:
interface Animal {name: string; } interface Cat extends Animal { meow(); }
function isCat(a: Animal): a is Cat { return a.name === ‘kitty’; }
var x: Animal;
if(isCat(x)) { x.meow(); // OK, x is Cat in this block }
This allows you to work with not only typeof and instanceof checks, which need a type that JavaScript understands, but now you can work with interfaces and do custom analysis. Guard functions are denoted by their “a is X” return type, which returns boolean and signals to the compiler if what the expected type now is.
Intersection types
Common patterns in JS that haven’t been easy to express in TypeScript are mixins and extending existing classes with new methods. To help with this, we’re adding a new type operator ‘&’ that will combine two types together. While it was possible to do this before by creating a new interface that inherited from two other types, this tended to be clunky and couldn’t be used in the case you wanted to use it most: combining generic types.
This new & operator, called intersection, creates anonymous combinations of types.
function extend<T, U>(first: T, second: U): T & U { let result = <T & U> {}; for (let id in first) { result[id] = first[id]; }
for (let id in second) { if (!result.hasOwnProperty(id)) { result[id] = second[id]; } } return result; }
var x = extend({ a: “hello” }, { b: 42 }); x.a; // works x.b; // works
Abstract classes
A long-standing feature request for TypeScript has been supporting abstract classes. Similar in some ways to interfaces, abstract classes give you a way of creating a base class, complete with default implementations, that you can build from with the intention of it never being used directly outside of the class hierarchy.
abstract class A { foo(): number { return this.bar(); } abstract bar(): number; }
var a = new A(); // error, Cannot create an instance of the abstract class ‘A’
class B extends A { bar() { return 1; } }
var b = new B(); // success, all abstracts are defined
Generic type aliases
Leading up to TypeScript 1.6, type aliases were restricted to being simple aliases that shortened long type names. Unfortunately, without being able to make these generic, they had limited use. We now allow type aliases to be generic, giving them full expressive capability.
type switcharoo<T, U> = (u: U, t:T)=>T; var f: switcharoo<number, string>; f(“bob”, 4);
Potentially-breaking changes
Along with all the new features, we also spent some time tightening and fixing up a few areas of the system to generally work better, help you catch more errors, and be closer to how other tools work. In this release we now require that an object literal should be matched directly. We’ve also updated the module resolution logic to work more closely to what you would expect for the type of output module you selected. You can read the full list of potential breaking changes with their mitigations.
Object literal strictness
We’ve made object compatibility stricter to help catch a class of common bugs. You can learn more about this in the 1.6 beta post.
Improvements to module resolution
We’ve changed module resolution when doing CommonJS output to work more closely to how Node does module resolution. If a module name is non-relative, we now follow these steps to find the associated typings:
- Check in node_modules for <module name>.d.ts
- Search node_modules\<module name>\package.json for a typings field
- Look for node_modules\<module name>\index.d.ts
- Then we go one level higher and repeat the process
Please note: when we search through node_modules, we assume these are the packaged node modules which have type information and a corresponding .js file. As such, we resolve only .d.ts files (not .ts file) for non-relative names.
Previously, we treated all module names as relative paths, and therefore we would never properly look in node_modules. If you prefer the previous behavior, you can use the compiler flag “–moduleResolution classic”. We will continue to improve module resolution, including improvements to AMD, in upcoming releases.
Looking ahead
We’re excited to reveal all the new improvements to TypeScript and to hear your feedback. There’s lots to come, with more ES6 and ES7 features ahead. And we’re always open if you want to jump in.
0 comments