JSX 支援
JSX 是一種可嵌入的類 XML 語法。它旨在被轉換為有效的 JavaScript,但轉換的具體語義取決於實現。JSX 隨著 React 庫的普及而流行,此後也看到了其他應用。TypeScript 1.6 支援嵌入、型別檢查以及可選地直接將 JSX 編譯為 JavaScript。
新的 .tsx 副檔名和 as 運算子
TypeScript 1.6 引入了新的 .tsx 副檔名。此副檔名有兩層含義:它允許在 TypeScript 檔案中使用 JSX,並使新的 as 運算子成為型別轉換的預設方式(消除了 JSX 表示式與 TypeScript 字首型別轉換運算子之間的任何歧義)。例如
tsvar x = <any>foo;// is equivalent to:var x = foo as any;
使用 React
若要在 React 中使用 JSX 支援,您應該使用 React 型別定義。這些型別定義了 JSX 名稱空間,以便 TypeScript 可以正確地為 React 檢查 JSX 表示式。例如
ts/// <reference path="react.d.ts" />interface Props {name: string;}class MyComponent extends React.Component<Props, {}> {render() {return <span>{this.props.name}</span>;}}<MyComponent name="bar" />; // OK<MyComponent name={0} />; // error, `name` is not a number
使用其他 JSX 框架
JSX 元素名稱和屬性會根據 JSX 名稱空間進行驗證。請參閱 [[JSX]] Wiki 頁面,瞭解如何為您的框架定義 JSX 名稱空間。
輸出生成
TypeScript 附帶兩種 JSX 模式:preserve 和 react。
preserve模式會將 JSX 表示式保留在輸出中,供後續的轉換步驟處理。此外,輸出將具有.jsx副檔名。react模式將發出React.createElement呼叫,使用前無需經過 JSX 轉換,且輸出將具有.js副檔名。
有關在 TypeScript 中使用 JSX 的更多資訊,請參閱 [[JSX]] Wiki 頁面。
交集型別 (Intersection types)
TypeScript 1.6 引入了交集型別,它是聯合型別的邏輯補集。聯合型別 A | B 表示屬於 A 或 B 型別中的一種,而交集型別 A & B 表示同時屬於 A 和 B 型別的實體。
示例
tsfunction 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 });var s = x.a;var n = x.b;
tstype LinkedList<T> = T & { next: LinkedList<T> };interface Person {name: string;}var people: LinkedList<Person>;var s = people.name;var s = people.next.name;var s = people.next.next.name;var s = people.next.next.next.name;
tsinterface A {a: string;}interface B {b: string;}interface C {c: string;}var abc: A & B & C;abc.a = "hello";abc.b = "hello";abc.c = "hello";
更多資訊請參見 Issue #1256。
區域性型別宣告
現在的函式宣告內部可以出現區域性類、介面、列舉和類型別名宣告。區域性型別是塊級作用域的,類似於用 let 和 const 宣告的變數。例如
tsfunction f() {if (true) {interface T {x: number;}let v: T;v.x = 5;} else {interface T {x: string;}let v: T;v.x = "hello";}}
函式的推斷返回型別可能是函式內部宣告的區域性型別。函式的呼叫者無法引用此類區域性型別,但當然可以透過結構匹配來相容。例如
tsinterface Point {x: number;y: number;}function getPointFactory(x: number, y: number) {class P {x = x;y = y;}return P;}var PointZero = getPointFactory(0, 0);var PointOne = getPointFactory(1, 1);var p1 = new PointZero();var p2 = new PointZero();var p3 = new PointOne();
區域性型別可以引用封閉的型別引數,區域性類和介面本身也可以是泛型的。例如
tsfunction f3() {function f<X, Y>(x: X, y: Y) {class C {public x = x;public y = y;}return C;}let C = f(10, "hello");let v = new C();let x = v.x; // numberlet y = v.y; // string}
類表示式
TypeScript 1.6 增加了對 ES6 類表示式的支援。在類表示式中,類名是可選的;如果指定了類名,它僅在類表示式自身的作用域內有效。這類似於函式表示式的可選名稱。在類表示式之外無法引用類表示式的類例項型別,但當然可以透過結構匹配來相容。例如
tslet Point = class {constructor(public x: number, public y: number) {}public length() {return Math.sqrt(this.x * this.x + this.y * this.y);}};var p = new Point(3, 4); // p has anonymous class typeconsole.log(p.length());
擴充套件表示式
TypeScript 1.6 增加了對類擴充套件任意表達式的支援,該表示式會計算出一個建構函式。這意味著內建型別現在可以在類宣告中被擴充套件。
類之前的 extends 子句需要指定一個型別引用。現在它接受一個表示式,後面可選跟型別引數列表。該表示式的型別必須是一個建構函式型別,並且至少有一個構造簽名,其型別引數數量與 extends 子句中指定的型別引數數量相同。匹配的構造簽名的返回型別是類例項型別繼承自的基型別。實際上,這允許在 extends 子句中指定真實的類和“類表示式”。
一些示例
ts// Extend built-in typesclass MyArray extends Array<number> {}class MyError extends Error {}// Extend computed base classclass ThingA {getGreeting() {return "Hello from A";}}class ThingB {getGreeting() {return "Hello from B";}}interface Greeter {getGreeting(): string;}interface GreeterConstructor {new (): Greeter;}function getGreeterBase(): GreeterConstructor {return Math.random() >= 0.5 ? ThingA : ThingB;}class Test extends getGreeterBase() {sayHello() {console.log(this.getGreeting());}}
abstract 類和方法
TypeScript 1.6 為類及其方法增加了 abstract 關鍵字支援。抽象類允許擁有未實現的方法,且無法被例項化。
示例
tsabstract class Base {abstract getThing(): string;getOtherThing() {return "hello";}}let x = new Base(); // Error, 'Base' is abstract// Error, must either be 'abstract' or implement concrete 'getThing'class Derived1 extends Base {}class Derived2 extends Base {getThing() {return "hello";}foo() {super.getThing(); // Error: cannot invoke abstract members through 'super'}}var x = new Derived2(); // OKvar y: Base = new Derived2(); // Also OKy.getThing(); // OKy.getOtherThing(); // OK
泛型類型別名
在 TypeScript 1.6 中,類型別名可以是泛型的。例如
tstype Lazy<T> = T | (() => T);var s: Lazy<string>;s = "eager";s = () => "lazy";interface Tuple<A, B> {a: A;b: B;}type Pair<T> = Tuple<T, T>;
更嚴格的物件字面量賦值檢查
TypeScript 1.6 強制執行更嚴格的物件字面量賦值檢查,旨在捕獲多餘或拼寫錯誤的屬性。具體而言,當一個新的物件字面量被賦值給變數或作為非空目標型別的引數傳遞時,如果物件字面量指定了目標型別中不存在的屬性,則會報錯。
示例
tsvar x: { foo: number };x = { foo: 1, baz: 2 }; // Error, excess property `baz`var y: { foo: number; bar?: number };y = { foo: 1, baz: 2 }; // Error, excess or misspelled property `baz`
型別可以包含索引簽名,以明確指示允許存在額外的屬性
tsvar x: { foo: number; [x: string]: any };x = { foo: 1, baz: 2 }; // Ok, `baz` matched by index signature
ES6 生成器 (Generators)
TypeScript 1.6 增加了在面向 ES6 時對生成器的支援。
生成器函式可以像普通函式一樣帶有返回型別註解。該註解表示函式返回的生成器的型別。這是一個示例
tsfunction* g(): Iterable<string> {for (var i = 0; i < 100; i++) {yield ""; // string is assignable to string}yield* otherStringGenerator(); // otherStringGenerator must be iterable and element type assignable to string}
沒有型別註解的生成器函式可以進行型別推斷。因此在下例中,型別將根據 yield 語句進行推斷
tsfunction* g() {for (var i = 0; i < 100; i++) {yield ""; // infer string}yield* otherStringGenerator(); // infer element type of otherStringGenerator}
對 async 函式的實驗性支援
TypeScript 1.6 引入了在面向 ES6 時對 async 函式的實驗性支援。非同步函式旨在呼叫非同步操作並等待其結果,而不阻塞程式的正常執行。這是透過使用 ES6 相容的 Promise 實現,並將函式體轉換為相容形式,以便在非同步操作完成後恢復執行來實現的。
非同步函式是指帶有 async 修飾符的函式或方法。此修飾符通知編譯器需要進行函式體轉換,並將關鍵字 await 視為一元表示式而不是識別符號。非同步函式必須提供一個指向相容 Promise 型別的返回型別註解。只有在全域性定義了相容的 Promise 型別時,才能使用返回型別推斷。
示例
tsvar p: Promise<number> = /* ... */;async function fn(): Promise<number> {var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"return 1 + i;}var a = async (): Promise<number> => 1 + await p; // suspends execution.var a = async () => 1 + await p; // suspends execution. return type is inferred as "Promise<number>" when compiling with --target ES6var fe = async function(): Promise<number> {var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"return 1 + i;}class C {async m(): Promise<number> {var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"return 1 + i;}async get p(): Promise<number> {var i = await p; // suspend execution until 'p' is settled. 'i' has type "number"return 1 + i;}}
夜間構建版本 (Nightly builds)
雖然不是嚴格意義上的語言變更,但現在可以透過以下命令安裝夜間構建版本
npm install -g typescript@next
模組解析邏輯的調整
從 1.6 版本開始,當面向 'commonjs' 時,TypeScript 編譯器將使用一套不同的規則來解析模組名稱。這些 規則 旨在模擬 Node 使用的模組查詢過程。這實際上意味著 node 模組可以包含其型別定義資訊,而 TypeScript 編譯器將能夠找到它。不過,使用者可以透過使用 moduleResolution 命令列選項來覆蓋編譯器選擇的模組解析規則。可選值為
- 'classic' - 1.6 版本之前的 TypeScript 編譯器使用的模組解析規則
- 'node' - 類 Node 的模組解析
合併環境類與介面宣告
環境類宣告的例項側可以使用介面宣告進行擴充套件。類建構函式物件保持不變。例如
tsdeclare class Foo {public x: number;}interface Foo {y: string;}function bar(foo: Foo) {foo.x = 1; // OK, declared in the class Foofoo.y = "1"; // OK, declared in the interface Foo}
使用者自定義型別保護函式
TypeScript 1.6 增加了一種在 if 塊內收窄變數型別的新方法,作為 typeof 和 instanceof 的補充。使用者自定義型別保護函式是返回型別註解形式為 x is T 的函式,其中 x 是簽名中的已宣告引數,T 是任意型別。當在 if 塊中對變數呼叫使用者自定義型別保護函式時,該變數的型別將被收窄為 T。
示例
tsfunction isCat(a: any): a is Cat {return a.name === "kitty";}var x: Cat | Dog;if (isCat(x)) {x.meow(); // OK, x is Cat in this block}
tsconfig.json 中的 exclude 屬性支援
未指定 files 屬性的 tsconfig.json 檔案(因此隱式引用所有子目錄中的所有 *.ts 檔案)現在可以包含一個 exclude 屬性,用於指定要從編譯中排除的檔案和/或目錄列表。exclude 屬性必須是一個字串陣列,每個字串指定一個相對於 tsconfig.json 檔案位置的檔案或資料夾名稱。例如
{"": {"": "test.js"},"": ["node_modules", "test.ts", "utils/t2.ts"]}
exclude 列表不支援萬用字元。它必須只是一個檔案和/或目錄的列表。
--init 命令列選項
在目錄中執行 tsc --init 可在該目錄中建立一個包含預設預設值的初始 tsconfig.json。您可以選擇在 --init 後面傳遞命令列引數,以便在建立時將其存入初始的 tsconfig.json 中。