聯(lián)合類型有助于表示一個(gè)值的類型可以是多種類型之一的情況。比如,有一個(gè)API接命令行傳入string
類型,string[]
類型或者是一個(gè)返回string
的函數(shù)。你就可以這樣寫:
interface RunOptions {
program: string;
commandline: string[]|string|(() => string);
}
給聯(lián)合類型賦值也很直觀 -- 只要這個(gè)值能滿足聯(lián)合類型中任意一個(gè)類型那么就可以賦值給這個(gè)聯(lián)合類型:
var opts: RunOptions = /* ... */;
opts.commandline = '-hello world'; // OK
opts.commandline = ['-hello', 'world']; // OK
opts.commandline = [42]; // Error, 數(shù)字不是字符串或字符串?dāng)?shù)組
當(dāng)讀取聯(lián)合類型時(shí),你可以訪問類型共有的屬性:
if(opts.length === 0) { // OK, string和string[]都有'length'屬性
console.log("it's empty");
}
使用類型保護(hù),你可以輕松地使用聯(lián)合類型:
function formatCommandline(c: string|string[]) {
if(typeof c === 'string') {
return c.trim();
} else {
return c.join(' ');
}
}
隨著聯(lián)合類型可以表示有很多類型的場(chǎng)景,我們決定去改進(jìn)泛型調(diào)用的規(guī)范性。之前,這段代碼編譯不會(huì)報(bào)錯(cuò)(出乎意料):
function equal<T>(lhs: T, rhs: T): boolean {
return lhs === rhs;
}
// 之前沒有錯(cuò)誤
// 現(xiàn)在會(huì)報(bào)錯(cuò):在string和number之前沒有最佳的基本類型
var e = equal(42, 'hello');
通過聯(lián)合類型,你可以指定你想要的行為,在函數(shù)定義時(shí)或在調(diào)用的時(shí)候:
// '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
當(dāng)一個(gè)集合里有多種類型的值時(shí),聯(lián)合類型會(huì)為數(shù)組或其它地方提供更好的類型推斷:
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
聲明會(huì)被“提升”到所在作用域的頂端。這可能會(huì)引發(fā)一些讓人不解的bugs:
console.log(x); // meant to write 'y' here
/* later in the same block */
var x = 'hello';
TypeScript已經(jīng)支持新的ES6的關(guān)鍵字let
,聲明一個(gè)塊級(jí)作用域的變量。一個(gè)let
變量只能在聲明之后的位置被引用,并且作用域?yàn)槁暶魉膲K里:
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
只在設(shè)置目標(biāo)為ECMAScript 6 (--target ES6
)時(shí)生效。
const
聲明另一個(gè)TypeScript支持的ES6里新出現(xiàn)的聲明類型是const
。不能給一個(gè)const
類型變量賦值,只能在聲明的時(shí)候初始化。這對(duì)于那些在初始化之后就不想去改變它的值的情況下是很有幫助的:
const halfPi = Math.PI / 2;
halfPi = 2; // Error, can't assign to a `const`
const
只在設(shè)置目標(biāo)為ECMAScript 6 (--target ES6
)時(shí)生效。
TypeScript現(xiàn)已支持ES6模塊字符串。通過它可以方便地在字符串中嵌入任何表達(dá)式:
var name = "TypeScript";
var greeting = `Hello, ${name}! Your name has ${name.length} characters`;
當(dāng)編譯目標(biāo)為ES6之前的版本時(shí),這個(gè)字符串被分解為:
var name = "TypeScript!";
var greeting = "Hello, " + name + "! Your name has " + name.length + " characters";
JavaScript常用模式之一是在運(yùn)行時(shí)使用typeof
或instanceof
檢查表達(dá)式的類型。 在if
語(yǔ)句里使用它們的時(shí)候,TypeScript可以識(shí)別出這些條件并且隨之改變類型推斷的結(jié)果。
使用typeof
來檢查一個(gè)變量:
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
結(jié)合聯(lián)合類型使用typeof
和else
:
var x: string|HTMLElement = /* ... */;
if(typeof x === 'string') {
// x is string here, as shown above
} else {
// x is HTMLElement here
console.log(x.innerHTML);
}
結(jié)合類和聯(lián)合類型使用instanceof
:
class Dog { woof() { } }
class Cat { meow() { } }
var pet: Dog|Cat = /* ... */;
if(pet instanceof Dog) {
pet.woof(); // OK
} else {
pet.woof(); // Error
}
你現(xiàn)在可以使用type
關(guān)鍵字來為類型定義一個(gè)“別名”:
type PrimitiveArray = Array<string|number|boolean>;
type MyNumber = number;
type NgScope = ng.IScope;
type Callback = () => void;
類型別名與其原始的類型完全一致;它們只是簡(jiǎn)單的替代名。
const enum
(完全嵌入的枚舉)枚舉很有幫助,但是有些程序?qū)嶋H上并不需要它生成的代碼并且想要將枚舉變量所代碼的數(shù)字值直接替換到對(duì)應(yīng)位置上。新的const enum
聲明與正常的enum
在類型安全方面具有同樣的作用,只是在編譯時(shí)會(huì)清除掉。
const enum Suit { Clubs, Diamonds, Hearts, Spades }
var d = Suit.Diamonds;
Compiles to exactly:
var d = 1;
TypeScript也會(huì)在可能的情況下計(jì)算枚舉值:
enum MyFlags {
None = 0,
Neat = 1,
Cool = 2,
Awesome = 4,
Best = Neat | Cool | Awesome
}
var b = MyFlags.Best; // emits var b = 7;
-noEmitOnError
命令行選項(xiàng)TypeScript編譯器的默認(rèn)行為是當(dāng)存在類型錯(cuò)誤(比如,將string
類型賦值給number
類型)時(shí)仍會(huì)生成.js文件。這在構(gòu)建服務(wù)器上或是其它場(chǎng)景里可能會(huì)是不想看到的情況,因?yàn)橄M玫降氖且淮巍凹儍簟钡臉?gòu)建。新的noEmitOnError
標(biāo)記可以阻止在編譯時(shí)遇到錯(cuò)誤的情況下繼續(xù)生成.js代碼。
它現(xiàn)在是MSBuild工程的默認(rèn)行為;這允許MSBuild持續(xù)構(gòu)建以我們想要的行為進(jìn)行,輸出永遠(yuǎn)是來自純凈的構(gòu)建。
默認(rèn)情況下AMD模塊以匿名形式生成。這在使用其它工具(比如,r.js)處理生成的模塊的時(shí)可能會(huì)帶來麻煩。
新的amd-module name
標(biāo)簽允許給編譯器傳入一個(gè)可選的模塊名:
//// [amdModule.ts]
///<amd-module name='NamedModule'/>
export class C {
}
結(jié)果會(huì)把NamedModule
賦值成模塊名,做為調(diào)用AMDdefine
的一部分:
//// [amdModule.js]
define("NamedModule", ["require", "exports"], function (require, exports) {
var C = (function () {
function C() {
}
return C;
})();
exports.C = C;
});