原文是 What's new in TypeScript 的一部分html
TypeScript 有兩個特殊的類型,null 和 undefined,null
和 undefined
分別是它們的值。之前是不能顯式使用這些類型的,但如今 null
和 undefined
無論在什麼類型檢查模式下均可以用做類型名稱。node
之前的類型檢查器認爲 null
和 undefined
能夠賦值給任意變量。實際上,null
和 undefined
對每個類型都是有效的值,任何類型都不可能明肯定義不包含它們(所以不可能檢查到對它們的錯誤使用)。jquery
--strictNullChecks
--strictNullChecks
參數用於新的嚴格空檢查模式。git
在嚴格空檢查模式下, null
和 undefined
值都 不 屬於任何一個類型,它們只能賦值給本身這種類型或者 any
(有一個例外,undefined
也能夠賦值給 void
)。所以,在常規類型檢查模式下 T
和 T | ndefined
被認爲是等同的(由於 undefined
被看做 T
的子類型),但它們在嚴格類型檢查模式下是不一樣的類型,只有 T | undefined
類型容許出現 undefined
值。T
和 T | null
也是這種狀況。es6
// 使用 --strictNullChecks 參數編譯 let x: number; let y: number | undefined; let z: number | null | undefined; x = 1; // 正確 y = 1; // 正確 z = 1; // 正確 x = undefined; // 錯誤 y = undefined; // 正確 z = undefined; // 正確 x = null; // 錯誤 y = null; // 錯誤 z = null; // 正確 x = y; // 錯誤 x = z; // 錯誤 y = x; // 正確 y = z; // 錯誤 z = x; // 正確 z = y; // 正確
在嚴格空檢查模式下,編譯器要求在任意可能先進到的代碼路徑前,不容許 undefined
值的變量引用都必須已經賦值。github
// 使用 --strictNullChecks 參數編譯 let x: number; let y: number | null; let z: number | undefined; x; // 錯誤, 使用前未賦值 y; // 錯誤, 使用前未賦值 z; // 正確 x = 1; y = null; x; // 正確 y; // 正確
編譯器經過 基於控制流的類型分析 來檢查變量是否確實賦值. 稍後請進一步閱讀關於這個主題的細節。web
可選參數和屬性會自動將 undefined
加入它們的類型,哪怕在它們的類型申明中沒有特別指定 undefined
。好比下面兩個類型就是一致的。typescript
// 使用 --strictNullChecks 參數編譯 type T1 = (x?: number) => string; // x 類型是 number | undefined type T2 = (x?: number | undefined) => string; // x 類型是 number | undefined
若是一個對象是 null
或 undefined
,訪問它的屬性會引起編譯錯誤,對 null
或 undefined
進行函數調用也會引起編譯錯誤。不過類型檢查進行了擴展,支持對非空和非未定義類型進行檢查。shell
// 使用 --strictNullChecks 參數編譯 declare function f(x: number): string; let x: number | null | undefined; if (x) { f(x); // 正確, 這裏 x 的類型是 number } else { f(x); // 錯誤, 這裏 x 是 number? } let a = x != null ? f(x) : ""; // a 的類型是字符串 let b = x && f(x); // b 的類型是 string | 0 | null | undefined
非空和非未定義類型檢查容許使用 ==
、!=
、===
、或者 !==
運算符來與 null
或者 undefined
進行比較,好比 x != null
或 x === undefined
。具體效果與 JavaScript 的語義一致。(例如,雙等號運算符檢查兩個值,無論哪個是指定的,而三等號運算符只檢查指定的值)。json
之前的類型控制只能檢查局部變量和參數。而如今它能夠檢查「帶點的名稱〔譯者注:帶點指對象後面的點號運算符〕」,這類名稱由變量或參數以及後面的一個或多個屬性訪問組成。
interface Options { location?: { x?: number; y?: number; }; } function foo(options?: Options) { if (options && options.location && options.location.x) { const x = options.location.x; // x 的類型是 number } }
對帶點號和名稱的類型控制也會應用於用戶定義的類型控制功能,以及 typeof
和 instanceof
運算符,並且算不須要 --strictNullChecks
編譯參數。
對帶點號的名稱的類型控制會在對其中任意部分賦值後失敗。好比,x.y.z
的類型控制在 x
、x.y
或 x.y.z
賦值後將失去效用。
表達式運算符容許操做數類型包括 null
或/和 undefined
,但結果必定是非空非未定義的類型。
// 使用 --strictNullChecks 參數編譯 function sum(a: number | null, b: number | null) { return a + b; // 結果類型是 number }
&&
運算符的會根據在操做數的類型來添加 null
或/和 undefined
類型到右操做數的類型中。||
則會從左操做數的類型中去掉 null
和 undefined
後,再用於推導結果類型。
// 使用 --strictNullChecks 參數編譯 interface Entity { name: string; } let x: Entity | null; let s = x && x.name; // s 類型是 string | null let y = x || { name: "test" }; // y 類型是 Entity
在嚴格空檢查模型下,null
和 undefined
不會 擴展爲 any
。
let z = null; // z 是 null
由於類型擴展,在常規類型檢查模式下 z
被推導爲 any
,但在嚴格空類型檢查模式下對 z
的類型推導結果仍然是 null
(而且,因爲沒有指定類型,null
是 z
惟一可能的值)。
新的 !
後置運算符用於斷言它的操做數在檢查器不能推斷的狀況下是非空非未定義的。舉例說明:x!
申明 x
的值不多是 null
或 undefined
。與 <T>x
和 x as T
這兩種形式的類型申明類似,在生成 JavaScript 代碼時只是簡單地去掉了 !
非空斷言運算符。
// 使用 --strictNullChecks 參數編譯 function validateEntity(e?: Entity) { // 若是 e 是 null 或者無效的 Entity,拋出異常 } function processEntity(e?: Entity) { validateEntity(e); let s = e!.name; // 斷言 e 非空,而後訪問它的 name 屬性 }
這個新特性設置爲能夠在嚴格空檢查模式和常規類型檢查模式下均可使用。具體來講,在常規類型檢查模式下,null
和 undefined
類型會自動從聯合類型中剔除(由於它們已是其它類型的子類型了),!
非空斷言運算符容許存在但在常規類型檢查模式下不會有任何做用。這樣一來,使用了非空非未定義類型的申明文件就能夠向後兼容,在常規類型檢查模型下使用。
在實際應用中,嚴格空檢查模式要求全部用於編譯的文件都是可識別空和未定義的。
TypeScript 2.0 實現了基於控制流的類型分析,用於控制局部變量和參數。以前,用於類型控制的類型分析侷限於 if
語句和 ?:
條件表達式,並不能用於賦值和控制流結構,如 return
和 break
語句。無論這個擁有聯合類型的變量和參數出如今什麼地方,TypeScript 2.0 讓類型檢查分析貫穿於全部可能的流程,包括可能會產生極特別類型(縮小範圍的類型)的語句和表達式。
function foo(x: string | number | boolean) { if (typeof x === "string") { x; // x 是 string 類型 x = 1; x; // x 是 number 類型 } x; // x 是 number | boolean 類型 } function bar(x: string | number) { if (typeof x === "number") { return; } x; // x 是 string 類型 }
基於控制流的類型分析與 --strictNullChecks
模式極爲相關,由於可空類型使用聯合類型來表示:
function test(x: string | null) { if (x === null) { return; } x; // 在函數後面的部分,x 是 string 類型 }
此外,--strictNullChecks
模式中,對不容許爲 undefined
變量,基於控制流的類型分析還包含了 精確的賦值分析。
function mumble(check: boolean) { let x: number; // 這個類型不容許 undefined 值 x; // 錯誤, x 是 undefined if (check) { x = 1; x; // 正確 } x; // 錯誤, x 有多是 undefined x = 2; x; // 正確 }
TypeScript 2.0 開始支持推斷(或可識別)聯合類型。特別指出,TS 編譯器如今支持限制聯合類型來對類型進行保護。這基於代碼中對標識屬性的檢查。這項功能也被擴展到 switch
語句。
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) { // 下面的 switch 語句中,每一個 case 子句都限制了 s 的類型。 // 根據對標識屬性值的判斷,這使得既然不申明類型也能夠根據推斷出來的類型訪問其它屬性。 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 == v
、x.p === v
、x.p != v
或 x.p !== v
這樣的表達式,p
和 v
是 string 字面類型〔譯者注:常量〕或者是一個 string 字面常量的聯合〔譯者注:好比 "type1" | "type2" | "type3" 這樣〕。x
有一個 p
屬性,該屬性有一個可能的值 v
,標識屬性類型控制據此能夠推斷 x
更精確的類型。
注意,目前咱們僅支持標識屬性是 string 字面量類型的狀況。咱們計劃後面添加對布爾和數值字面量的支持。
never
類型TypeScript 2.0 引入了新的基本類型 never
。never
類型值表現爲從未發生。 具體說來,never
用於函數的返回值申明,而這個函數實際沒有返回任何東西。在類型控制做用下,never
是不可能做爲變量類型的。
never
類型有以下一些特徵:
never
是全部類型的子類型,便可以賦值給任意類型。never
的子類型,因此不能賦值給 never
(never
本身除外)。return
語句,或者 return
語句返回的就是 結果爲 never
的表達式,又或者函數結尾不可達(由控制流程分析判斷),則推斷函數的返回類型是 never
。never
,全部 return
語句(若是有的話)必須返回結果爲 never
的表達式,而且必定不可能到達函數結尾。由於 never
是任何類型的子類型,因此通常不會在聯合類型中指定,而且若是函數中推導出來有其它類型返回,never
就會被忽略。
一些返回 never
的函數示例:
// 函數不能到達結束點,返回類型是 never function error(message: string): never { throw new Error(message); } // 推導返回類型是 never function fail() { return error("Something failed"); } // 函數不能到達結束點,返回類型是 never function infiniteLoop(): never { while (true) { } }
一些使用返回 never
的函數的函數示例:
// 推導返回類型是 number function move1(direction: "up" | "down") { switch (direction) { case "up": return 1; case "down": return -1; } return error("Should never get here"); } // 推導返回類型是 number function move2(direction: "up" | "down") { return direction === "up" ? 1 : direction === "down" ? -1 : error("Should never get here"); } // 推導返回類型是 T function check<T>(x: T | undefined) { return x || error("Undefined value"); }
因爲 never
能夠賦值給任意類型,返回 never
的函數能夠用於返回特定類型的回調函數:
function test(cb: () => string) { let s = cb(); return s; } test(() => "hello"); test(() => fail()); test(() => { throw new Error(); })
如今經過 readonly
修飾符,屬性或索引能夠被申明爲只讀的。
只讀屬性能夠擁有初始化器,也能夠定義它的類的構造函數中賦值,其它狀況下都是不容許賦值的。
另外,有一些狀況會產生 隱式的 只讀申明。
get
訪問器沒有 set
訪問器的屬性被認爲是隻讀的。const
變量是隻讀的。import
語句中申明的實體是隻讀的。import * as foo from "foo"
中申明瞭 foo
,這時 foo.x
是隻讀的。interface Point { readonly x: number; readonly y: number; } var p1: Point = { x: 10, y: 20 }; p1.x = 5; // 錯誤, p1.x 只讀 var p2 = { x: 1, y: 1 }; var p3: Point = p2; // 正確, p2 的只讀別名〔由於 Point 中的屬性定義爲 readonly〕 p3.x = 5; // 錯誤, p3.x 只讀 p2.x = 5; // 正確, 同時也改變了 p3.x,由於 p3 是 p2 的(只讀)別名
class Foo { readonly a = 1; readonly b: string; constructor() { this.b = "hello"; // 構造函數中容許賦值 } }
let a: Array<number> = [0, 1, 2, 3, 4]; let b: ReadonlyArray<number> = a; b[5] = 5; // 錯誤, 元素只讀 b.push(5); // 錯誤, 沒有 push 方法 (由於它是 array 的變種) b.length = 3; // 錯誤, length 只讀 a = b; // 錯誤, 因爲變種,部分方法已經不存在了
this
繼爲類和接口指定 this
類型以後,函數和方法也能夠申明它們所指望的 this
類型了。
默認狀況下函數內部的 this
類型是 any
。從 TypeScript 2.0 開始,能夠顯示的指代一個 this
參數。this
參數不是一個真實的參數,並且它必須放在參數列表的第一位:
function f(this: void) { // 確保在這個獨立的函數中不會用到 `this` }
this
參數在功能庫中,this
參數可用於申明回調函數如何調用。
interface UIElement { addClickListener(onclick: (this: void, e: Event) => void): void; }
this: void
表示 addClickListener
但願 onclick
是一個不須要 this
類型的函數。
如今若是須要使用 this
調用:
class Handler { info: string; onClickBad(this: Handler, e: Event) { // 天啊,這裏用了 this,使用這個回調在運行時會致使巨大的錯誤 this.info = e.message; }; } let h = new Handler(); uiElement.addClickListener(h.onClickBad); // 錯誤!
--noImplicitThis
TypeScript 2.0 中加入了一個參數,標記全部函數中的 this
都沒有申明類型。
tsconfig.json
支持 Glob支持 Glob 啦!!支持 Glob 是最受歡迎特性中的一個.
"include"
和 "exclude"
兩個參數支持使用 Glob 形式的文件模板。
{ "compilerOptions": { "module": "commonjs", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, "outFile": "../../built/local/tsc.js", "sourceMap": true }, "include": [ "src/**/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] }
支持的 Glob 通配符包括:
*
匹配 0 個或更多字符(不包含目錄分隔符)?
匹配 1 個字符(不包含目錄分隔符)**/
遞歸匹配任意子目錄若是一段 Glob 模板只包含 *
或 .*
,則只有支持的文件擴展名被包含在內(如:默認的 .ts
、.tsx
和 .d.ts
,若是 allowJs
設置爲 true,則還有 .js
和 .jsx
)。
若是 "files"
和 "include"
都未指定,編譯器默認包含全部包含目錄及子目錄下的 TypeScript(.ts
、.d.ts
和 .tsx
) 文件,不過要排除 "exclude"
中指定的那些。若是 allowJs
設置爲 true,JS 文件 (.js
and .jsx
) 也會包含在內。
若是指定了 "files"
或 "include"
屬性,編譯器會合並兩個屬性指定的文件。"outDir"
選項指定目錄中的文件老是被排除在外,除非在 "files"
中特別指定("exclude"
屬性中指定的也是這樣)。
"include"
包含的文件能夠被 "exclude"
屬性過濾。然而 "files"
屬性指定的文件則無論 "exclude"
屬性的設置。"exclude"
屬性未設置時,默認會排除 node_modules
、bower_components
和 jspm_packages
目錄。
TypeScript 2.0 提供了一系列的模塊解決方案工具來通知編譯器在哪裏找到給定模塊的申明。
參閱 模塊解決方案文檔進行具體瞭解。
baseUrl
是 AMD 模塊加載系統經常使用的辦法,它描述了模塊在運行時應該從哪個目錄「展開」。全部未指定相對路徑的導入都假定相對於 baseUrl
。
{ "compilerOptions": { "baseUrl": "./modules" } }
導入 "moduleA"
時會在 ./modules/moduleA
中查找。
import A from "moduleA";
有時候模塊並不直接放在 baseUrl 下。加載器使用一個映射配置在模塊名稱和文件之間創建映射關係。參閱
RequireJs 文檔 和 SystemJS 文檔.
TypeScript 編譯器支持在 tsconfig.json
文件中使用 "pathes"
屬性申明相似的映射。
導入模塊 "jquery"
會在運行時轉換爲 "node_modules/jquery/dist/jquery.slim.min.js"
.
{ "compilerOptions": { "baseUrl": "./node_modules", "paths": { "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
文件看起來就像這樣:
{ "compilerOptions": { "rootDirs": [ "src/views", "generated/templates/views" ] } }
--traceResolution
提供了一個方便的方式來讓編譯器知道該如何找到模塊。
tsc --traceResolution
若是你不想在使用一個新模塊的時候花時間去寫它的申明,你如今能夠簡單地使用速配環境來達到目的。
declare module "hot-new-module";
從速配模塊導入的變量都是 any 類型。
import x, {y} from "hot-new-module"; x(y);
以前想經過模塊加載器擴展(例如 AMD 或者 SystemJS) 十分不易;之前須要爲每一個資源定義環境模塊申明。
TypeScript 2.0 支持使用通配符(*
)申明一「組」模塊名稱;這種方法使得只須要爲擴展申明一次,而沒必要爲每一個資源進行申明。
declare module "*!text" { const content: string; export default content; } // 有些會用另外一種形式 declare module "json!*" { const value: any; export default value; }
這樣就能夠導入與 "*!text"
或 "json!*"
匹配的資源。
import fileContent from "./xyz.txt!text"; import data from "json!http://example.com/data.json"; console.log(data, fileContent);
在從無類型代碼中遷移代碼時,通配符模塊也很是有用。若是與模塊申明的速配環境結合,很是容易地就能將一系列的模塊看成 any
申明。
declare module "myLibrary/*";
從 myLibrary
下的模塊導入的內容都被編譯器看成 any
類型;這直接關閉了這些模塊的形式或類型檢查。
import { readFile } from "myLibrary/fileSystem/readFile`; readFile(); // readFile 是 'any'
有些庫被設置爲容許多處模塊加載器加載,或者不須要使用加載器(全局變量)。知名的有 UMD 和 Isomorphic 模塊。這些庫既能夠經過 import 導入使用,也能夠經過設置全局變量來使用。
例如:
export const isPrime(x: number): boolean; export as namespace mathLib;
以後這個庫在模塊中經過導入使用:
import { isPrime } from "math-lib"; isPrime(2); mathLib.isPrime(2); // 錯誤: 不能在模塊內使用全局定義
它也能夠看成全局變量使用,但只能在腳本中這樣作。(腳本指不包含導入導出的文件。)
mathLib.isPrime(2);
如今類中能夠定義可選的類屬性和方法,這在接口中早就實現併爲你們所熟知了。
class Bar { a: number; b?: number; f() { return 1; } g?(): number; // 可選方法的方法體能夠省略掉 h?() { return 2; } }
在 --strictNullChecks
模式下編譯時,可選屬性和方法的類型中會自動包含 undefined
。所以上面示例中的 b
屬性是 number | undefined
類型,而 g
方法是 (() => number) | undefined
類型。
類型控制會在適當的時機將 undefined
從類型中剝離出去:
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 }
類構造函數能夠申明爲 private
或 protected
。具備私有構造函數的類不能在外部實例化,也不能被繼承。具備保護構造函數的類不能在外部實例化,但能夠被繼承。
class Singleton { private static instance: Singleton; private constructor() { } static getInstance() { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } } let e = new Singleton(); // 錯誤: 'Singleton' 的構造函數是私有的 let v = Singleton.getInstance();
抽象類能夠申明抽象屬性和抽象訪問器。子類中須要定義抽象屬性,或者繼續標記爲抽象的。抽象屬性不能初始化。抽象訪問器不能有函數體。
abstract class Base { abstract name: string; abstract get value(); abstract set value(v: number); } class Derived extends Base { name = "derived"; value = 1; }
若是一個對象字面量的全部屬性都符合某個索引特性,那麼這個對象字面量類型就就能夠賦值給它。這樣對於須要一個映射或字典做爲參數的函數,就能夠接受初始化爲相應對象字面量的變量了:
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" }); // 正確 httpService("", headers); // 如今正確,而之前是錯誤的
--lib
包含內置類型申明輸入 --lib
可讓 ES6/ES2015 內置 API 申明僅限於 target: ES6
。經過 --lib
選項你能夠選擇一些內置 API 申明組包含在項目中。假如你但願運行時支持 Map
、Set
和 Promise
(大部分新瀏覽器都支持),只須要使用參數 --lib es2015.collection,es2015.promise
。
與之相似,也能夠從項目中排除一些不須要的申明,好比你在 node 項目中就不須要包含 DOM,那麼可使用 --lib es5,es6
。
這裏有一個支持的 API 組列表:
tsc --target es5 --lib es5,es2015.promise
"compilerOptions": { "lib": ["es5", "es2015.promise"] }
--noUnusedParameters
和 --noUnusedLocals
標記未使用的申明TypeScript 2.0 有兩個參數可幫助你保持代碼簡潔。--noUnusedParameters
參數會將未使用的函數和方法參數標記爲錯誤。--noUnusedLocals
會將未使用的局部(未導出)申明,包含變量、函數、類、導入等,標記出來。在使用 --noUnusedLocals
參數的狀況下,未使用的私有類成員也會被標記爲錯誤。
import B, { readFile } from "./b"; // ^ 錯誤: `B` 申明但未使用 readFile(); export function write(message: string, args: string[]) { // ^^^^ 錯誤: 'arg' 申明但未使用 console.log(message); }
以 _
開始的參數申明會被「未使用」參數檢查忽略。例如:
function returnNull(_a) { // 正確 return null; }
.js
擴展名TypeScript 2.0 之前,模塊識別會忽略擴展名。好比,導入 import d from "./moduleA.js"
,編譯器會在 ./moduleA.js.ts
或者 ./moduleA.js.d.ts
中查找 "moduleA.js"
中的定義。這使得經過 URI 標識來使用一些像SystemJS 那樣的構建或加載工具比較困難。
TypeScript 2.0 的編譯器會在 ./moduleA.ts
或 ./moduleA.d.ts
中去查找 "moduleA.js"
中的定義。
之前的版本中 target: es5
和 module: es6
參數不一樣合併使用,但如今能夠了。這能促進使用基於 ES2015 的 Tree-Shaking 工具,好比 rollup。
如今容許函數參數列表或調用參數列表後面出現逗號了。這在 Stage-3 ECMAScript 建議 中提出,對 ES3/ES5/ES6 均有效。
function foo( bar: Bar, baz: Baz, // 容許參數列表後面的逗號 ) { // 實現... } foo( bar, baz, // 容許調用參數列表後面的逗號 );
--skipLibCheck
TypeScript 2.0 添加了一個新編譯參數 --skipLibCheck
,這個參數會讓編譯器跳過對申明文件(擴展名是 .d.ts
的文件)的類型檢查。若是一個程序包含大量的申明文件,編譯器會花不少時間去檢查這些已知沒有錯誤的申明。若是跳過對這些申明文件的檢查,編譯時間會獲得顯著提高。
因爲一個文件中的申明可能影響其它文件的類型檢查,因此使用 --skipLibCheck
參數後可能會致使某些錯誤被不被探測到。好比,一個非申明文件使用了某個申明文件中申明的類型,那只有在申明文件被檢查的時候纔可能發現並報告錯誤。固然這種狀況極不容易發生。
在多個申明文件中爲某個接口定義了相同的成員,這一般會致使重複定義錯誤。
TypeScript 2.0 放寬了這個限制。若是兩個定義塊中出現重複定義,只要它們是 徹底相同的 類型就不會有問題。
在同一個定義塊中定義重複的類型仍然是錯誤的。
interface Error { stack?: string; } interface Error { code?: string; path?: string; stack?: string; // 正確 }
--declarationDir
--declarationDir
容許在與生成的 JavaScript 文件不一樣的位置生成申明文件。