TypeScript 2.0

Null 和 Undefined 感知型別

TypeScript 有兩個特殊型別:Null 和 Undefined,它們分別具有值 nullundefined。以前無法顯式命名這些型別,但現在無論型別檢查模式如何,都可以將 nullundefined 用作型別名稱。

型別檢查器以前認為 nullundefined 可以賦值給任何型別。實際上,nullundefined每種型別的有效值,因此無法專門排除它們(也就無法檢測到對它們的錯誤使用)。

--strictNullChecks

strictNullChecks 切換到一種新的嚴格空值檢查模式。

在嚴格空值檢查模式下,nullundefined包含在每種型別的域中,它們只能賦值給自身和 any 型別(唯一的例外是 undefined 也可以賦值給 void)。因此,雖然在常規型別檢查模式下 TT | undefined 被視為同義(因為 undefined 被視為任何 T 的子型別),但在嚴格型別檢查模式下它們是不同的型別,只有 T | undefined 允許使用 undefined 值。TT | null 的關係也是如此。

示例
ts
// Compiled with --strictNullChecks
let x: number;
let y: number | undefined;
let z: number | null | undefined;
x = 1; // Ok
y = 1; // Ok
z = 1; // Ok
x = undefined; // Error
y = undefined; // Ok
z = undefined; // Ok
x = null; // Error
y = null; // Error
z = null; // Ok
x = y; // Error
x = z; // Error
y = x; // Ok
y = z; // Error
z = x; // Ok
z = y; // Ok

使用前賦值檢查

在嚴格空值檢查模式下,編譯器要求對不包含 undefined 的型別的區域性變數的每次引用,必須在所有可能的先行程式碼路徑中先進行賦值。

示例
ts
// Compiled with --strictNullChecks
let x: number;
let y: number | null;
let z: number | undefined;
x; // Error, reference not preceded by assignment
y; // Error, reference not preceded by assignment
z; // Ok
x = 1;
y = null;
x; // Ok
y; // Ok

編譯器透過執行基於控制流的型別分析來檢查變數是否已明確賦值。有關此主題的更多詳細資訊,請參閱後文。

可選引數和屬性

可選引數和屬性會自動將 undefined 新增到它們的型別中,即使它們的型別註解中沒有顯式包含 undefined。例如,以下兩種型別是相同的

ts
// Compiled with --strictNullChecks
type T1 = (x?: number) => string; // x has type number | undefined
type T2 = (x?: number | undefined) => string; // x has type number | undefined

非空和非未定義型別守衛

如果物件或函式屬於包含 nullundefined 的型別,則屬性訪問或函式呼叫會產生編譯時錯誤。但是,型別守衛已擴充套件為支援非空和非未定義檢查。

示例
ts
// Compiled with --strictNullChecks
declare function f(x: number): string;
let x: number | null | undefined;
if (x) {
f(x); // Ok, type of x is number here
} else {
f(x); // Error, type of x is number? here
}
let a = x != null ? f(x) : ""; // Type of a is string
let b = x && f(x); // Type of b is string | 0 | null | undefined

非空和非未定義型別守衛可以使用 ==!====!== 運算子與 nullundefined 進行比較,例如 x != nullx === undefined。對主體變數型別的影響準確反映了 JavaScript 語義(例如,雙等號運算子無論指定哪一個值都會檢查兩個值,而三等號僅檢查指定的值)。

型別守衛中的點號名稱

型別守衛以前僅支援檢查區域性變數和引數。現在型別守衛支援檢查“點號名稱”(dotted names),即由變數或引數名稱後跟一個或多個屬性訪問組成。

示例
ts
interface Options {
location?: {
x?: number;
y?: number;
};
}
function foo(options?: Options) {
if (options && options.location && options.location.x) {
const x = options.location.x; // Type of x is number
}
}

點號名稱的型別守衛也適用於使用者定義的型別守衛函式,以及 typeofinstanceof 運算子,並且不依賴於 strictNullChecks 編譯器選項。

對於點號名稱的型別守衛,在對該點號名稱的任何部分賦值後將失效。例如,對於 x.y.z 的型別守衛,在對 xx.yx.y.z 賦值後將不再起作用。

表示式運算子

表示式運算子允許運算元型別包含 null 和/或 undefined,但產生的值始終是非空和非未定義型別。

ts
// Compiled with --strictNullChecks
function sum(a: number | null, b: number | null) {
return a + b; // Produces value of type number
}

&& 運算子根據右運算元型別中是否存在 null 和/或 undefined 將其新增到結果型別中,而 || 運算子則從左運算元的型別中移除 nullundefined

ts
// Compiled with --strictNullChecks
interface Entity {
name: string;
}
let x: Entity | null;
let s = x && x.name; // s is of type string | null
let y = x || { name: "test" }; // y is of type Entity

型別拓寬

在嚴格空值檢查模式下,nullundefined 型別不會被拓寬為 any

ts
let z = null; // Type of z is null

在常規型別檢查模式下,由於拓寬,z 的推斷型別為 any;但在嚴格空值檢查模式下,z 的推斷型別為 null(因此,如果沒有型別註解,nullz 的唯一可能值)。

非空斷言運算子

可以使用新的 ! 字尾表示式運算子來斷言其運算元在型別檢查器無法得出該結論的上下文中是非空且非未定義的。具體而言,操作 x! 產生一個 x 型別的值,並排除 nullundefined。與 <T>xx as T 形式的型別斷言類似,! 非空斷言運算子在編譯生成的 JavaScript 程式碼中會被簡單地刪除。

ts
// Compiled with --strictNullChecks
function validateEntity(e?: Entity) {
// Throw exception if e is null or invalid entity
}
function processEntity(e?: Entity) {
validateEntity(e);
let s = e!.name; // Assert that e is non-null and access name
}

相容性

新特性的設計使其既可以在嚴格空值檢查模式下使用,也可以在常規型別檢查模式下使用。特別地,在常規型別檢查模式下,nullundefined 型別會自動從聯合型別中移除(因為它們是所有其他型別的子型別),並且 ! 非空斷言表示式運算子在常規型別檢查模式下是允許使用的,但沒有任何效果。因此,為了向後相容,更新為使用 Null 和 Undefined 感知型別的宣告檔案仍然可以在常規型別檢查模式下使用。

實際上,嚴格空值檢查模式要求編譯中的所有檔案都必須是 Null 和 Undefined 感知的。

基於控制流的型別分析

TypeScript 2.0 實現了針對區域性變數和引數的基於控制流的型別分析。以前,為型別守衛執行的型別分析僅限於 if 語句和 ?: 條件表示式,並不包括賦值和諸如 returnbreak 語句等控制流結構的影響。在 TypeScript 2.0 中,型別檢查器會分析語句和表示式中所有可能的控制流,從而為宣告為聯合型別的區域性變數或引數在任何給定位置生成最具體的型別(細化型別)。

示例
ts
function foo(x: string | number | boolean) {
if (typeof x === "string") {
x; // type of x is string here
x = 1;
x; // type of x is number here
}
x; // type of x is number | boolean here
}
function bar(x: string | number) {
if (typeof x === "number") {
return;
}
x; // type of x is string here
}

基於控制流的型別分析在 strictNullChecks 模式下尤為重要,因為可空型別是使用聯合型別表示的。

ts
function test(x: string | null) {
if (x === null) {
return;
}
x; // type of x is string in remainder of function
}

此外,在 strictNullChecks 模式下,基於控制流的型別分析包括對不允許值 undefined 的型別的區域性變數的明確賦值分析

ts
function mumble(check: boolean) {
let x: number; // Type doesn't permit undefined
x; // Error, x is undefined
if (check) {
x = 1;
x; // Ok
}
x; // Error, x is possibly undefined
x = 2;
x; // Ok
}

標記聯合型別(Tagged union types)

TypeScript 2.0 實現了對標記(或可辨識)聯合型別的支援。具體而言,TS 編譯器現在支援基於鑑別屬性(discriminant property)測試來縮小聯合型別的型別守衛,並將此功能擴充套件到了 switch 語句中。

示例
ts
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
// In the following switch statement, the type of s is narrowed in each case clause
// according to the value of the discriminant property, thus allowing the other properties
// of that variant to be accessed without a type assertion.
switch (s.kind) {
case "square":
return s.size * s.size;
case "rectangle":
return s.width * s.height;
case "circle":
return Math.PI * s.radius * s.radius;
}
}
function test1(s: Shape) {
if (s.kind === "square") {
s; // Square
} else {
s; // Rectangle | Circle
}
}
function test2(s: Shape) {
if (s.kind === "square" || s.kind === "rectangle") {
return;
}
s; // Circle
}

鑑別屬性型別守衛是形式為 x.p == vx.p === vx.p != vx.p !== v 的表示式,其中 p 是一個屬性,v 是字串字面量型別或字串字面量聯合型別的表示式。鑑別屬性型別守衛會將 x 的型別縮小為 x 中那些具有鑑別屬性 p 且值為 v 可能值之一的組成型別。

請注意,目前我們僅支援字串字面量型別的鑑別屬性。我們打算稍後增加對布林值和數字字面量型別的支援。

never 型別

TypeScript 2.0 引入了新的原始型別 nevernever 型別表示從不出現的值的型別。具體而言,never 是從不返回的函式的返回型別,也是型別守衛中從不為真的變數的型別。

never 型別具有以下特徵:

  • never 是每種型別的子型別,並可賦值給每種型別。
  • 沒有任何型別是 never 的子型別或可賦值給 never(除了 never 本身)。
  • 在沒有返回型別註解的函式表示式或箭頭函式中,如果函式沒有 return 語句,或者只有 never 型別的表示式的 return 語句,並且函式的終點是不可達的(根據控制流分析確定),則函式的推斷返回型別為 never
  • 在具有顯式 never 返回型別註解的函式中,所有 return 語句(如果有)必須具有 never 型別的表示式,且函式的終點必須不可達。

由於 never 是每種型別的子型別,它始終會從聯合型別中被省略,並且在存在其他返回型別的情況下,它在函式返回型別推斷中會被忽略。

一些返回 never 的函式示例:

ts
// Function returning never must have unreachable end point
function error(message: string): never {
throw new Error(message);
}
// Inferred return type is never
function fail() {
return error("Something failed");
}
// Function returning never must have unreachable end point
function infiniteLoop(): never {
while (true) {}
}

一些使用返回 never 的函式的示例:

ts
// Inferred return type is number
function move1(direction: "up" | "down") {
switch (direction) {
case "up":
return 1;
case "down":
return -1;
}
return error("Should never get here");
}
// Inferred return type is number
function move2(direction: "up" | "down") {
return direction === "up"
? 1
: direction === "down"
? -1
: error("Should never get here");
}
// Inferred return type is T
function check<T>(x: T | undefined) {
return x || error("Undefined value");
}

由於 never 可以賦值給每種型別,因此當需要返回更具體型別的回撥時,可以使用返回 never 的函式。

ts
function test(cb: () => string) {
let s = cb();
return s;
}
test(() => "hello");
test(() => fail());
test(() => {
throw new Error();
});

只讀屬性和索引簽名

現在可以使用 readonly 修飾符宣告屬性或索引簽名。

只讀屬性可以有初始化器,也可以在同一類宣告的建構函式中賦值,但除此之外禁止對只讀屬性賦值。

此外,實體在以下幾種情況下是隱式只讀的:

  • 聲明瞭 get 訪問器但沒有 set 訪問器的屬性被視為只讀。
  • 在列舉物件的型別中,列舉成員被視為只讀屬性。
  • 在模組物件的型別中,匯出的 const 變數被視為只讀屬性。
  • import 語句中宣告的實體被視為只讀。
  • 透過 ES2015 名稱空間匯入訪問的實體被視為只讀(例如,當 foo 被宣告為 import * as foo from "foo" 時,foo.x 是隻讀的)。
示例
ts
interface Point {
readonly x: number;
readonly y: number;
}
var p1: Point = { x: 10, y: 20 };
p1.x = 5; // Error, p1.x is read-only
var p2 = { x: 1, y: 1 };
var p3: Point = p2; // Ok, read-only alias for p2
p3.x = 5; // Error, p3.x is read-only
p2.x = 5; // Ok, but also changes p3.x because of aliasing
ts
class Foo {
readonly a = 1;
readonly b: string;
constructor() {
this.b = "hello"; // Assignment permitted in constructor
}
}
ts
let a: Array<number> = [0, 1, 2, 3, 4];
let b: ReadonlyArray<number> = a;
b[5] = 5; // Error, elements are read-only
b.push(5); // Error, no push method (because it mutates array)
b.length = 3; // Error, length is read-only
a = b; // Error, mutating methods are missing

為函式指定 this 的型別

繼在類或介面中指定 this 的型別之後,函式和方法現在也可以宣告它們期望的 this 型別。

預設情況下,函式內部 this 的型別是 any。從 TypeScript 2.0 開始,您可以提供一個顯式的 this 引數。this 引數是假引數,位於函式引數列表的開頭。

ts
function f(this: void) {
// make sure `this` is unusable in this standalone function
}

回撥函式中的 this 引數

庫也可以使用 this 引數來宣告回撥函式將如何被呼叫。

示例
ts
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}

this: void 表示 addClickListener 期望 onclick 是一個不需要 this 型別的函式。

現在,如果您使用 this 對呼叫程式碼進行註解

ts
class Handler {
info: string;
onClickBad(this: Handler, e: Event) {
// oops, used this here. using this callback would crash at runtime
this.info = e.message;
}
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!

--noImplicitThis

TypeScript 2.0 還添加了一個新標誌,用於標記函式中所有未提供顯式型別註解而使用 this 的情況。

tsconfig.json 中的 Glob 支援

Glob 支援來了!!Glob 支援是最受要求的功能之一

Glob 風格的檔案模式由 includeexclude 兩個屬性支援。

示例
{
"": "commonjs",
"": true,
"": true,
"": "../../built/local/tsc.js",
"": true
},
"": ["src/**/*"],
"": ["node_modules", "**/*.spec.ts"]
}

支援的 glob 萬用字元有:

  • * 匹配零個或多個字元(不包括目錄分隔符)
  • ? 匹配任意單個字元(不包括目錄分隔符)
  • **/ 遞迴匹配任何子目錄

如果 glob 模式的段僅包含 *.*,則僅包含具有受支援副檔名的檔案(例如,預設情況下包含 .ts.tsx.d.ts,如果將 allowJs 設定為 true,則還包含 .js.jsx)。

如果未指定 filesinclude,編譯器預設包含所在目錄及子目錄下所有 TypeScript(.ts.d.ts.tsx)檔案,除非使用 exclude 屬性排除。如果將 allowJs 設定為 true,也會包含 JS 檔案(.js.jsx)。

如果指定了 filesinclude 屬性,編譯器將改用這兩個屬性所包含檔案的並集。除非透過 files 屬性顯式包含,否則目錄中使用 outDir 編譯器選項指定的檔案始終會被排除(即使指定了 exclude 屬性)。

使用 include 包含的檔案可以使用 exclude 屬性進行過濾。但是,使用 files 屬性顯式包含的檔案無論是否排除都始終被包含。未指定時,exclude 屬性預設排除 node_modulesbower_componentsjspm_packages 目錄。

模組解析增強:BaseUrl、路徑對映、rootDirs 和跟蹤

TypeScript 2.0 提供了一組額外的模組解析控制項,以告知編譯器在何處查詢給定模組的宣告。

有關詳細資訊,請參閱模組解析文件。

Base URL

在執行期間模組被“部署”到單個資料夾的 AMD 模組載入器應用程式中,使用 baseUrl 是一種常見做法。所有具有裸說明符名稱的模組匯入都被假定為相對於 baseUrl

示例
{
"": "./modules"
}
}

現在,對 "moduleA" 的匯入將在 ./modules/moduleA 中查詢。

ts
import A from "moduleA";

路徑對映

有時模組並不直接位於 baseUrl 下。載入器使用對映配置在執行期間將模組名稱對映到檔案,請參閱 RequireJs 文件SystemJS 文件

TypeScript 編譯器支援在 tsconfig.json 檔案中使用 paths 屬性宣告此類對映。

示例

例如,對模組 "jquery" 的匯入將在執行時轉換為 "node_modules/jquery/dist/jquery.slim.min.js"

{
"": "./node_modules",
"": {
"jquery": ["jquery/dist/jquery.slim.min"]
}
}

使用 paths 還允許進行更復雜的對映,包括多個回退位置。考慮一種專案配置,其中某些模組在一個位置可用,而其餘模組在另一個位置。

使用 rootDirs 的虛擬目錄

使用 ‘rootDirs’,您可以告知編譯器構成此“虛擬”目錄的 根目錄;這樣編譯器就可以解析這些“虛擬”目錄內的相對模組匯入,就好像它們被合併在一個目錄中一樣。

示例

假設有此專案結構:

src └── views └── view1.ts (imports './template1') └── view2.ts generated └── templates └── views └── template1.ts (imports './view2')

構建步驟會將 /src/views/generated/templates/views 中的檔案複製到輸出中的同一目錄。在執行期間,檢視可以期望其模板與其相鄰,因此應該使用相對名稱 "./template" 來匯入它。

rootDirs 指定了一組根目錄,其內容預計會在執行時合併。因此,按照我們的示例,tsconfig.json 檔案應如下所示:

{
"": ["src/views", "generated/templates/views"]
}
}

跟蹤模組解析

traceResolution 提供了一種簡單的方法來了解模組是如何被編譯器解析的。

shell
tsc --traceResolution

簡寫環境模組宣告

如果您不想花時間在開始使用新模組之前編寫宣告,現在可以使用簡寫宣告來快速入門。

declarations.d.ts
ts
declare module "hot-new-module";

來自簡寫模組的所有匯入都將具有 any 型別。

ts
import x, { y } from "hot-new-module";
x(y);

模組名稱中的萬用字元

使用模組載入器擴充套件(例如 AMDSystemJS)匯入非程式碼資源以前並不容易;此前必須為每個資源定義環境模組宣告。

TypeScript 2.0 支援使用萬用字元 (*) 來宣告“一系列”模組名稱;這樣,只需為副檔名進行一次宣告,而不必為每個資源都進行宣告。

示例
ts
declare module "*!text" {
const content: string;
export default content;
}
// Some do it the other way around.
declare module "json!*" {
const value: any;
export default value;
}

現在,您可以匯入匹配 "*!text""json!*" 的內容。

ts
import fileContent from "./xyz.txt!text";
import data from "json!http://example.com/data.json";
console.log(data, fileContent);

當從非型別化的程式碼庫遷移時,萬用字元模組名稱可能更有用。結合簡寫環境模組宣告,可以輕鬆地將一組模組宣告為 any

示例
ts
declare module "myLibrary/*";

myLibrary 下任何模組的所有匯入都將被編譯器視為具有 any 型別;從而關閉了對這些模組的形狀或型別的任何檢查。

ts
import { readFile } from "myLibrary/fileSystem/readFile`;
readFile(); // readFile is 'any'

支援 UMD 模組定義

有些庫被設計為用於許多模組載入器,或者不使用模組載入(全域性變數)。這些被稱為 UMDIsomorphic 模組。這些庫可以透過匯入或全域性變數訪問。

例如:

math-lib.d.ts
ts
export const isPrime(x: number): boolean;
export as namespace mathLib;

該庫隨後可以作為模組內的匯入使用

ts
import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // ERROR: can't use the global definition from inside a module

它也可以作為全域性變數使用,但僅限於指令碼內部。(指令碼是沒有任何匯入或匯出的檔案。)

ts
mathLib.isPrime(2);

可選類屬性

現在可以在類中宣告可選屬性和方法,類似於介面中已允許的操作。

示例
ts
class Bar {
a: number;
b?: number;
f() {
return 1;
}
g?(): number; // Body of optional method can be omitted
h?() {
return 2;
}
}

當在 strictNullChecks 模式下編譯時,可選屬性和方法會自動包含 undefined 在其型別中。因此,上述 b 屬性的型別為 number | undefined,上述 g 方法的型別為 (() => number) | undefined。型別守衛可用於去除型別的 undefined 部分。

ts
function test(x: Bar) {
x.a; // number
x.b; // number | undefined
x.f; // () => number
x.g; // (() => number) | undefined
let f1 = x.f(); // number
let g1 = x.g && x.g(); // number | undefined
let g2 = x.g ? x.g() : 0; // number
}

私有和受保護的建構函式

類建構函式可以標記為 privateprotected。具有私有建構函式的類不能在類主體外部例項化,也不能被擴充套件。具有受保護建構函式的類不能在類主體外部例項化,但可以被擴充套件。

示例
ts
class Singleton {
private static instance: Singleton;
private constructor() {}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
}
let e = new Singleton(); // Error: constructor of 'Singleton' is private.
let v = Singleton.getInstance();

抽象屬性和訪問器

抽象類可以宣告抽象屬性和/或訪問器。任何子類都需要宣告這些抽象屬性或被標記為抽象。抽象屬性不能有初始化器。抽象訪問器不能有主體。

示例
ts
abstract class Base {
abstract name: string;
abstract get value();
abstract set value(v: number);
}
class Derived extends Base {
name = "derived";
value = 1;
}

隱式索引簽名

如果物件字面量中的所有已知屬性都可以賦值給索引簽名,則該物件字面量型別現在可以賦值給具有該索引簽名的型別。這使得可以將初始化為物件字面量的變數作為引數傳遞給期望對映或字典的函式。

ts
function httpService(path: string, headers: { [x: string]: string }) {}
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
};
httpService("", { "Content-Type": "application/x-www-form-urlencoded" }); // Ok
httpService("", headers); // Now ok, previously wasn't

使用 --lib 包含內建型別宣告

獲取 ES6/ES2015 內建 API 宣告以前僅限於 target: ES6。現在引入了 lib;透過 lib,您可以指定一組要包含在專案中的內建 API 宣告組。例如,如果您期望執行環境支援 MapSetPromise(例如當今大多數現代瀏覽器),只需包含 --lib es2015.collection,es2015.promise。同樣,您可以排除不想包含在專案中的宣告,例如,如果您在節點專案中使用 --lib es5,es6,則可以排除 DOM。

以下是可用 API 組的列表:

  • dom
  • webworker
  • es5
  • es6 / es2015
  • es2015.core
  • es2015.collection
  • es2015.iterable
  • es2015.promise
  • es2015.proxy
  • es2015.reflect
  • es2015.generator
  • es2015.symbol
  • es2015.symbol.wellknown
  • es2016
  • es2016.array.include
  • es2017
  • es2017.object
  • es2017.sharedmemory
  • scripthost
示例
bash
tsc --target es5 --lib es5,es2015.promise
"compilerOptions": {
"": ["es5", "es2015.promise"]
}

使用 --noUnusedParameters--noUnusedLocals 標記未使用的宣告

TypeScript 2.0 有兩個新標誌,可幫助您維護乾淨的程式碼庫。noUnusedParameters 會將任何未使用的函式或方法引數標記為錯誤。noUnusedLocals 會將任何未使用的(非匯出)區域性宣告(如變數、函式、類、匯入等)標記為錯誤。此外,類中未使用的私有成員在 noUnusedLocals 下也會被標記為錯誤。

示例
ts
import B, { readFile } from "./b";
// ^ Error: `B` declared but never used
readFile();
export function write(message: string, args: string[]) {
// ^^^^ Error: 'arg' declared but never used.
console.log(message);
}

_ 開頭命名的引數宣告不受未使用引數檢查的影響。例如:

ts
function returnNull(_a) {
// OK
return null;
}

模組識別符號允許 .js 副檔名

在 TypeScript 2.0 之前,模組識別符號始終被假定為沒有副檔名;例如,給定匯入 import d from "./moduleA.js",編譯器會在 ./moduleA.js.ts./moduleA.js.d.ts 中查詢 "moduleA.js" 的定義。這使得使用像 SystemJS 這樣期望在模組識別符號中使用 URI 的捆綁/載入工具變得困難。

在 TypeScript 2.0 中,編譯器將在 ./moduleA.ts./moduleA.d.ts 中查詢 "moduleA.js" 的定義。

支援 ‘target : es5’ 與 ‘module: es6’

以前被標記為無效的標誌組合,現在支援 target: es5module: es6。這應該有助於使用基於 ES2015 的 tree-shaker,如 rollup

函式引數和實參列表中的尾隨逗號

現在允許在函式引數和實參列表中使用尾隨逗號。這是對 Stage-3 ECMAScript 提案 的實現,該提案可以向下編譯為有效的 ES3/ES5/ES6。

示例
ts
function foo(
bar: Bar,
baz: Baz // trailing commas are OK in parameter lists
) {
// Implementation...
}
foo(
bar,
baz // and in argument lists
);

新的 --skipLibCheck

TypeScript 2.0 添加了一個新的 skipLibCheck 編譯器選項,該選項會跳過宣告檔案(副檔名為 .d.ts 的檔案)的型別檢查。當程式包含大型宣告檔案時,編譯器會花費大量時間檢查已知不包含錯誤的宣告,跳過宣告檔案的型別檢查可以顯著縮短編譯時間。

由於一個檔案中的宣告可能會影響其他檔案中的型別檢查,因此指定 skipLibCheck 時可能無法檢測到某些錯誤。例如,如果非宣告檔案擴充了宣告檔案中宣告的型別,則可能會產生僅在檢查該宣告檔案時才報告的錯誤。然而,在實踐中,這種情況很少見。

允許跨宣告的重複識別符號

這是重複定義錯誤的一個常見來源。多個宣告檔案在介面上定義相同的成員。

TypeScript 2.0 放寬了這一限制,只要型別相同,就允許跨塊出現重複識別符號。

在同一塊內,仍然不允許重複定義。

示例
ts
interface Error {
stack?: string;
}
interface Error {
code?: string;
path?: string;
stack?: string; // OK
}

新的 --declarationDir

declarationDir 允許在與 JavaScript 檔案不同的位置生成宣告檔案。

TypeScript 文件是一個開源專案。透過 傳送 Pull Request 來幫助我們改進這些頁面 ❤

此頁面的貢獻者
MHMohamed Hegazy (52)
OTOrta Therox (13)
EIEugene Ilyin (1)
ABAndrew Branch (1)
ECErrol Cleary (1)
10+

最後更新:2026 年 3 月 27 日