TypeScript 1.4

TypeScript 1.4

联合类型

概观

联合类型是表达可以是几种类型之一的值的有效方式。例如,您可能有一个运行程序的 API,该程序将命令行作为一个string,一个string[]或返回string的一个函数,你现在可以写:

interface RunOptions { program: string; commandline: string[]|string|(() => string }

对联合类型的赋值非常直观 - 任何可以赋给联合类型成员之一的赋值都可以赋给联合:

var opts: RunOptions = /* ... */; opts.commandline = '-hello world'; // OK opts.commandline = ['-hello', 'world']; // OK opts.commandline = [42]; // Error, number is not string or string[]

从联合类型读取时,可以看到它们共享的任何属性:

if (opts.length === 0) { // OK, string and string[] both have 'length' property console.log("it's empty" }

使用 Type Guards,您可以轻松使用联合类型的变量:

function formatCommandline(c: string|string[]) { if (typeof c === 'string') { return c.trim( } else { return c.join(' ' } }

更严格的泛型

使用联合类型可以表示各种类型的场景,我们决定改进某些通用调用的严格性。以前,像这样的代码会(令人惊讶地)编译时没有错误:

function equal<T>(lhs: T, rhs: T): boolean { return lhs === rhs; } // Previously: No error // New behavior: Error, no best common type between 'string' and 'number' var e = equal(42, 'hello'

使用联合类型,您现在可以在函数声明站点和调用站点上指定所需的行为:

// 'choose' function where types must match function choose1<T>(a: T, b: T): T { return Math.random() > 0.5 ? a : b } var a = choose1('hello', 42 // Error var b = choose1<string|number>('hello', 42 // OK // 'choose' function where types need not match function choose2<T, U>(a: T, b: U): T|U { return Math.random() > 0.5 ? a : b } var c = choose2('bar', 'foo' // OK, c: string var d = choose2('hello', 42 // OK, d: string|number

更好的类型推断

联合类型还允许在阵列和其他可能在集合中具有多种值的地方进行更好的类型推断:

var x = [1, 'hello']; // x: Array<string|number> x[0] = 'world'; // OK x[0] = false; // Error, boolean is not string or number

let 声明

在 JavaScript 中,var声明被“悬挂”到其封闭范围的顶部。这可能会导致错误:

console.log(x // meant to write 'y' here /* later in the same block */ var x = 'hello';

let现在在 TypeScript 中支持的新 ES6 关键字声明了一个具有更直观的“块”语义的变量。一个let变量只能在声明后被引用,并且被定义在定义它的语法块的范围内:

if (foo) { console.log(x // Error, cannot refer to x before its declaration let x = 'hello'; } else { console.log(x // Error, x is not declared in this block }

let仅在定位 ECMAScript 6(--target ES6)时可用。

const 声明

TypeScript 支持的另一个新的 ES6 声明类型是const。一个const变量可能不被赋值,并且必须在声明的地方初始化。这对于不想在初始化后更改值的声明很有用:

const halfPi = Math.PI / 2; halfPi = 2; // Error, can't assign to a `const`

const仅在定位 ECMAScript 6(--target ES6)时可用。

模板字符串

TypeScript 现在支持 ES6 模板字符串。这些是在字符串中嵌入任意表达式的简单方法:

var name = "TypeScript"; var greeting = `Hello, ${name}! Your name has ${name.length} characters`;

编译到 ES6 之前的目标时,字符串被分解:

var name = "TypeScript!"; var greeting = "Hello, " + name + "! Your name has " + name.length + " characters";

类型保护

JavaScript 中常见的模式是在运行时使用typeofinstanceof检查表达式的类型。TypeScript 现在可以理解这些条件,并将在if块中使用时相应地更改类型推断。

使用typeof测试一个变量:

var x: any = /* ... */; if(typeof x === 'string') { console.log(x.subtr(1) // Error, 'subtr' does not exist on 'string' } // x is still any here x.unknown( // OK

使用带有联合类型的typeofelse

var x: string | HTMLElement = /* ... */; if(typeof x === 'string') { // x is string here, as shown above } else { // x is HTMLElement here console.log(x.innerHTML }

使用带类和联合类型的instanceof

class Dog { woof() { } } class Cat { meow() { } } var pet: Dog|Cat = /* ... */; if (pet instanceof Dog) { pet.woof( // OK } else { pet.woof( // Error }

类型别名

您现在可以使用type关键字为类型定义别名

type PrimitiveArray = Array<string|number|boolean>; type MyNumber = number; type NgScope = ng.IScope; type Callback = () => void;

类型别名与原始类型完全相同;他们只是替代名称。

const enum (完全内联枚举)

枚举非常有用,但有些程序实际上并不需要生成的代码,并且只需将枚举成员的所有实例与它们的数字等值内联即可受益。新的const enum声明就像一个常规enum的类型安全一样工作,但在编译时完全消除。

const enum Suit { Clubs, Diamonds, Hearts, Spades } var d = Suit.Diamonds;

完全编译为:

var d = 1;

在可能的情况下,TypeScript 现在也将计算枚举值:

enum MyFlags { None = 0, Neat = 1, Cool = 2, Awesome = 4, Best = Neat | Cool | Awesome } var b = MyFlags.Best; // emits var b = 7;

-noEmitOnError 命令行选项

TypeScript 编译器的默认行为是,如果存在类型错误(例如试图将赋给string一个 number),仍然会发出 .js 文件。这在构建服务器或其他需要“干净”构建的输出的情况下可能不合需要。新标志noEmitOnError防止编译器在发生错误时发出.js代码。

这现在是 MSBuild 项目的默认值;这允许 MSBuild 增量构建按预期工作,因为输出只能在干净构建中生成。

AMD 模块名称

默认情况下,AMD 模块是匿名生成的。当使用其他工具来处理生成的模块(例如捆绑器r.js)时,这可能会导致问题。

amd-module name标签允许将可选模块名称传递给编译器:

//// [amdModule.ts] ///<amd-module name='NamedModule'/> export class C { }

作为调用 AMD define的一部分,将导致为该模块分配NamedModule名称:

//// [amdModule.js] define("NamedModule", ["require", "exports"], function (require, exports) { var C = (function () { function C() { } return C; })( exports.C = C; }