[译]TypeScript 2.0 Beta发布

今天我们非常兴奋地推出了TypeScript 2.0 beta版。如果你还不熟悉TypeScript,现在你就可以去我们的网站上学习。

获取beta版,你可以下载TypeScript 2.0 Beta for Visual Studio 2015 (此更新需要VS 2015 Update 3),或者运行

npm install -g typescript@beta

这个版本包含大量新特性,如新的方式获取.d.ts文件,但是这里的一些特性仅仅是对其了解。

非空类型

nullundefined是JavaScript bugs中最常见的两个来源。在TypeScript 2.0 之前,nullundefined存在每一类型域中。这意味着如果你有一个带有string类型参数的函数,你不能肯定是单一类型的,实际上有可能是string类型,也有可能是null类型。

在TypeScript 2.0,新的--strictNullChecks编译参数改变这一不确定性。string类型就是string类型,number类型就是number类型。

let foo: string = null; // 错误!

如果你为空呢?我们已经带来两个新的类型:nullundefined。正如你所料,null仅仅是null,undefined仅仅是undefined。对它们自己而言作用不大,但是你可以在联合类型中使用它们去定义是否可以包含null/undefined

let foo: string | null = null; // 正确!

由于作为开发者的你可能经常比编辑器的类型系统懂得更多,因此我们还推出了一个后缀操作符!,这个操作符可以从任何一个表达式从排除nullundefined

declare let strs: string[] | undefined;

// 错误! 'strs' 也许是undefined.
let upperCased = strs.map(s => s.toUpperCase());

// 'strs!' 意味着我们确定它不是'undefined', 因此我们可以调用'map'.
let lowerCased = strs!.map(s => s.toLowerCase());

基于控制流的类型分析

TypeScript对处理可空类型的支持成为可能,要归功于在整个程序中跟踪类型的变化。在2.0中,我们已经开始使用控制流分析,以便更好地了解在指定的位置是什么类型。例如,考虑下面这个函数。

/**
 * @param recipients An array of recipients, or a comma-separated list of recipients.
 * @param body Primary content of the message.
 */
function sendMessage(recipients: string | string[], body: string) {
 if (typeof recipients === "string") {
 recipients = recipients.split(",");
 }

// TypeScript 知道这里的'recipients'是'string[]'类型.
 recipients = recipients.filter(isValidAddress);
 for (let r of recipients) {
 // ...
 }
}

注意,在if块内赋值后,TypeScript知道它已经被处理成为了一个string类型的数组。这类事情可以在早期发现问题并节省你在调试上花费的时间。

let bestItem: Item;
for (let item of items) {
 if (item.id === 42) bestItem = item;
}

// 错误! 如果'items'是空的,'bestItem' 可能还没有被初始化。
let itemName = bestItem.name;

我们非常感谢Ivo Gabe de Wolff,他参与这一特性的实施工作,这也开始了他的论文项目并成长为TypeScript本身的一部分。

简易模块声明

有时候你仅仅想要告诉TypeScript有一个模块存在,并且你可能不关心它具体的内容是什么样子的。以前你要像下面这样写:

declare module "foo" {
 var x: any;
 export = x;
}

但是这样太麻烦的,因此我们使声明模块变得更加简易并且摆脱了样板。在TypeScript 2.0 中你可以这么写

declare module "foo";
declare module "bar";

当你准备好最终要写一个包含具体内容的模块时,你可以返回这些声明并定义你需要的结构。

如果你依靠一个有很多模块的软件包呢?为每一个模块书写一遍可能是痛苦的,但是TypeScript 2.0 通过使用通配符*使之变得容易。

declare module "foo/*";

现在您可以导入任何以foo/开头的路径,TypeScript会认为它存在。
你可以利用这一点,如果你的模块加载器也知道如何导入基于一个特定的模式。例如:

declare module "*!text" {
 const content: string;
 export = content;
}

现在每当你导入一个结尾带有!text的路径时,TypeScript就会知道导入的是string类型。

import text = require("./hello.txt!text");
text.toLowerCase();

关于模块这一部分,博客描述的太简单了,很多人可能不能明白,建议看看GitHub上的这部分内容

下一步

你可能想知道的一个特性是在ES3和ES5中支持async/await,最初,这是定于2.0版本。然而,合理的实现async/await,我们需要重写TypeScript的emitter,这会引起一系列的变化。这样做的同时还要保持TypeScript快速更新,就需要大量的工作和对细节的关注。虽然我们对于今天的实现充满了信心,但是信心不是彻底的测试,并且需要更多的时间用于async/await的稳定。你可以在TypeScript 2.1 中期待它的出现,如果你想要跟踪进度,在GitHub上的Pull request当前是公开的

TypeScript 2.0 还充满了许多有用的新功能,随着时间的推移我们将推出更多细节。如果你想听到更多的新特性,你可以看一下我们的wiki。在未来的几周内,一个更加稳定的候选版本将发布,随后最终的正式版将会发布。

我们很乐意听听你的任何反馈,无论是在下面的评论或GitHub上。黑客快乐!