TypeScript現(xiàn)在有兩個特殊的類型:Null和Undefined, 它們的值分別是null
和undefined
。 以前這是不可能明確地命名這些類型的,但是現(xiàn)在 null
和undefined
不管在什么類型檢查模式下都可以作為類型名稱使用。
以前類型檢查器認為null
和undefined
賦值給一切。實際上,null
和undefined
是每一個類型的有效值, 并且不能明確排除它們(因此不可能檢測到錯誤)。
--strictNullChecks
--strictNullChecks
可以切換到新的嚴格空檢查模式中。
在嚴格空檢查模式中,null
和undefined
值不再屬于任何類型的值,僅僅屬于它們自己類型和any
類型的值 (還有一個例外, undefined
也能賦值給void
)。因此,盡管在常規(guī)類型檢查模式下T
和T | undefined
被認為是相同的 (因為 undefined
被認為是任何T
的子類型),但是在嚴格類型檢查模式下它們是不同的, 并且僅僅 T | undefined
允許有undefined
值,T
和T | null
的關(guān)系同樣如此。
// 使用--strictNullChecks參數(shù)進行編譯的
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
類型的局部變量在使用之前必須先賦值。
// 使用--strictNullChecks參數(shù)進行編譯
let x: number;
let y: number | null;
let z: number | undefined;
x; // 錯誤,使用前未賦值
y; // 錯誤,使用前未賦值
z; // 正確
x = 1;
y = null;
x; // 正確
y; // 正確
編譯器通過執(zhí)行基于控制流的類型分析檢查變量明確被賦過值。在本篇文章后面會有進一步的細節(jié)。
可選參數(shù)和屬性會自動把undefined
添加到他們的類型中,即使他們的類型注解明確不包含undefined
。例如,下面兩個類型是完全相同的:
// 使用--strictNullChecks參數(shù)進行編譯
type T1 = (x?: number) => string; // x的類型是 number | undefined
type T2 = (x?: number | undefined) => string; // x的類型是 number | undefined
如果對象或者函數(shù)的類型包含null
和undefined
,那么訪問屬性或調(diào)用函數(shù)時就會產(chǎn)生編譯錯誤。因此,對類型保護進行了擴展,以支持對非null和非undefined的檢查。
// 使用--strictNullChecks參數(shù)進行編譯
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的類型是string
let b = x && f(x); // b的類型是 string | 0 | null | undefined
非null和非undefined類型保護可以使用==
、!=
、===
或!==
操作符和null
或undefined
進行比較,如x != null
或x === undefined
。對被試變量類型的影響準確地反映了JavaScript的語義(比如,雙等號運算符檢查兩個值無論你指定的是null還是undefined,然而三等于號運算符僅僅檢查指定的那一個值)。
類型保護以前僅僅支持對局部變量和參數(shù)的檢查?,F(xiàn)在類型保護支持檢查由變量或參數(shù)名稱后跟一個或多個訪問屬性組成的“點名稱”。
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
}
}
點名稱的類型保護和用戶定義的類型保護函數(shù),還有typeof
和instanceof
操作符一起工作,并且不依賴--strictNullChecks
編譯參數(shù)。
對點名稱進行類型保護后給點名稱任一部分賦值都會導(dǎo)致類型保護無效。例如,對x.y.z
進行了類型保護后給x
、x.y
或x.y.z
賦值,都會導(dǎo)致x.y.z
類型保護無效。
表達式操作符允許運算對象的類型包含null
和/或undefined
,但是總是產(chǎn)生非null和非undefined類型的結(jié)果值。
// 使用--strictNullChecks參數(shù)進行編譯
function sum(a: number | null, b: number | null) {
return a + b; // 計算的結(jié)果值類型是number
}
&&
操作符添加null
和/或undefined
到右邊操作對象的類型中取決于當前左邊操作對象的類型,||
操作符從左邊聯(lián)合類型的操作對象的類型中將null
和undefined
同時刪除。
// 使用--strictNullChecks參數(shù)進行編譯
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
在常規(guī)類型檢查模式中,由于擴展,會推斷z
的類型是any
,但是在嚴格空檢查模式中,推斷z
是null
類型(因此,如果沒有類型注釋,null
是z
的唯一值)。
在上下文中當類型檢查器無法斷定類型時,一個新的后綴表達式操作符!
可以用于斷言操作對象是非null和非undefined類型的。具體而言,運算x!
產(chǎn)生一個不包含null
和undefined
的x
的值。斷言的形式類似于<T>x
和x as T
,!
非空斷言操作符會從編譯成的JavaScript代碼中移除。
// 使用--strictNullChecks參數(shù)進行編譯
function validateEntity(e?: Entity) {
// 如果e是null或者無效的實體,就會拋出異常
}
function processEntity(e?: Entity) {
validateEntity(e);
let s = e!.name; // 斷言e是非空并訪問name屬性
}
這些新特性是經(jīng)過設(shè)計的,使得它們能夠在嚴格空檢查模式和常規(guī)類型檢查模式下都能夠使用。尤其是在常規(guī)類型檢查模式中,null
和undefined
類型會自動從聯(lián)合類型中刪除(因為它們是其它所有類型的子類型),!
非空斷言表達式操作符也被允許使用但是沒有任何作用。因此,聲明文件使用null和undefined敏感類型更新后,在常規(guī)類型模式中仍然是可以向后兼容使用的。
在實際應(yīng)用中,嚴格空檢查模式要求編譯的所有文件都是null和undefined敏感類型。
TypeScript 2.0實現(xiàn)了對局部變量和參數(shù)的控制流類型分析。以前,對類型保護進行類型分析僅限于if
語句和?:
條件表達式,并且不包括賦值和控制流結(jié)構(gòu)的影響,例如return
和break
語句。使用TypeScript 2.0,類型檢查器會分析語句和表達式所有可能的控制流,在任何指定的位置對聲明為聯(lián)合類型的局部變量或參數(shù)產(chǎn)生最可能的具體類型(縮小范圍的類型)。
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
模式中尤為重要,因為可空類型使用聯(lián)合類型來表示:
function test(x: string | null) {
if (x === null) {
return;
}
x; // 在函數(shù)的剩余部分中,x類型是string
}
而且,在--strictNullChecks
模式中,基于控制流的分析包括,對類型不允許為undefined
的局部變量有明確賦值的分析。
function mumble(check: boolean) {
let x: number; // 類型不允許為undefined
x; // 錯誤,x是undefined
if (check) {
x = 1;
x; // 正確
}
x; // 錯誤,x可能是undefi
x = 2;
x; // 正確
}
TypeScript 2.0實現(xiàn)了標記(或區(qū)分)聯(lián)合類型。具體而言,TS編譯器現(xiàn)在支持類型保護,基于判別屬性的檢查來縮小聯(lián)合類型的范圍,并且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語句中,s的類型在每一個case中都被縮小
// 根據(jù)判別屬性的值,變量的其它屬性不使用類型斷言就可以被訪問
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
是一個屬性和字符串字面量類型或字符串字面量聯(lián)合類型的表達式。判別屬性類型保護縮小x
的類型到由判別屬性p
和v
的可能值之一組成的類型。
請注意,我們目前只支持字符串字面值類型的判別屬性。我們打算以后添加對布爾值和數(shù)字字面量類型的支持。
never
類型TypeScript 2.0引入了一個新原始類型never
。never
類型表示值的類型從不出現(xiàn)。具體而言,never
是永不返回函數(shù)的返回類型,也是變量在類型保護中永不為true的類型。
never
類型具有以下特征:
never
是所有類型的子類型并且可以賦值給所有類型。never
的子類型或能賦值給never
(never
類型本身除外)。return
語句,或者只有never
類型表達式的return
語句,并且如果函數(shù)是不可執(zhí)行到終點的(例如通過控制流分析決定的),則推斷函數(shù)的返回類型是never
。never
返回類型注解的函數(shù)中,所有return
語句(如果有的話)必須有never
類型的表達式并且函數(shù)的終點必須是不可執(zhí)行的。因為never
是每一個類型的子類型,所以它總是在聯(lián)合類型中被省略,并且在函數(shù)中只要其它類型被返回,類型推斷就會忽略never
類型。
一些返回never
函數(shù)的示例:
// 函數(shù)返回never必須無法執(zhí)行到終點
function error(message: string): never {
throw new Error(message);
}
// 推斷返回類型是never
function fail() {
return error("Something failed");
}
// 函數(shù)返回never必須無法執(zhí)行到終點
function infiniteLoop(): never {
while (true) {
}
}
一些函數(shù)返回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
可以賦值給每一個類型,當需要回調(diào)函數(shù)返回一個更加具體的類型時,函數(shù)返回never
類型可以用于檢測返回類型是否正確:
function test(cb: () => string) {
let s = cb();
return s;
}
test(() => "hello");
test(() => fail());
test(() => { throw new Error(); })
屬性或索引簽名現(xiàn)在可以使用readonly
修飾符聲明為只讀的。
只讀屬性可以初始化和在同一個類的構(gòu)造函數(shù)中被賦值,但是在其它情況下對只讀屬性的賦值是不允許的。
此外,有幾種情況下實體隱式只讀的:
get
訪問器而沒有使用set
訪問器被視為只讀的。const
變量被視為只讀屬性。import
語句中聲明的實體被視為只讀的。foo
當作import * as foo from "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的只讀別名
p3.x = 5; // 錯誤,p3.x是只讀的
p2.x = 5; // 正確,但是因為別名使用,同時也改變了p3.x
class Foo {
readonly a = 1;
readonly b: string;
constructor() {
this.b = "hello"; // 在構(gòu)造函數(shù)中允許賦值
}
}
let a: Array<number> = [0, 1, 2, 3, 4];
let b: ReadonlyArray<number> = a;
b[5] = 5; // 錯誤,元素是只讀的
b.push(5); // 錯誤,沒有push方法(因為這會修改數(shù)組)
b.length = 3; // 錯誤,length是只讀的
a = b; // 錯誤,缺少修改數(shù)組的方法
this
類型緊跟著類和接口,現(xiàn)在函數(shù)和方法也可以聲明this
的類型了。
函數(shù)中this
的默認類型是any
。從TypeScript 2.0開始,你可以提供一個明確的this
參數(shù)。this
參數(shù)是偽參數(shù),它位于函數(shù)參數(shù)列表的第一位:
function f(this: void) {
// 確保`this`在這個獨立的函數(shù)中無法使用
}
this
參數(shù)庫也可以使用this
參數(shù)聲明回調(diào)函數(shù)如何被調(diào)用。
interface UIElement {
addClickListener(onclick: (this: void, e: Event) => void): void;
}
this:void
意味著addClickListener
預(yù)計onclick
是一個this
參數(shù)不需要類型的函數(shù)。
現(xiàn)在如果你在調(diào)用代碼中對this
進行了類型注釋:
class Handler {
info: string;
onClickBad(this: Handler, e: Event) {
// 哎喲,在這里使用this.在運行中使用這個回調(diào)函數(shù)將會崩潰。
this.info = e.message;
};
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // 錯誤!
--noImplicitThis
TypeScript 2.0還增加了一個新的編譯選項用來標記函數(shù)中所有沒有明確類型注釋的this
的使用。
tsconfig.json
支持文件通配符文件通配符來啦??!支持文件通配符一直是最需要的特性之一。
類似文件通配符的文件模式支持兩個屬性"include"
和"exclude"
。
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"outFile": "../../built/local/tsc.js",
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
支持文件通配符的符號有:
*
匹配零個或多個字符(不包括目錄)?
匹配任意一個字符(不包括目錄)**/
遞歸匹配所有子目錄如果文件通配符模式語句中只包含*
或.*
,那么只匹配帶有擴展名的文件(例如默認是.ts
、.tsx
和.d.ts
,如果allowJs
設(shè)置為true
,.js
和.jsx
也屬于默認)。
如果"files"
和"include"
都沒有指定,編譯器默認包含所有目錄中的TypeScript文件(.ts
、.d.ts
和.tsx
),除了那些使用exclude
屬性排除的文件外。如果allowJs
設(shè)置為true,JS文件(.js
和.jsx
)也會被包含進去。
如果"files"
和"include"
都指定了,編譯器將包含這兩個屬性指定文件的并集。使用ourDir
編譯選項指定的目錄文件總是被排除,即使"exclude"
屬性指定的文件也會被刪除,但是files
屬性指定的文件不會排除。
"exclude"
屬性指定的文件會對"include"
屬性指定的文件過濾。但是對"files"
指定的文件沒有任何作用。當沒有明確指定時,"exclude"
屬性默認會排除node_modules
、bower_components
和jspm_packages
目錄。
TypeScript 2.0提供了一系列額外的模塊解析屬性告訴編譯器去哪里可以找到給定模塊的聲明。
更多詳情,請參閱模塊解析文檔。
使用了AMD模塊加載器并且模塊在運行時”部署“到單文件夾的應(yīng)用程序中使用baseUrl
是一種常用的做法。所有非相對名稱的模塊導(dǎo)入被認為是相對于baseUrl
的。
{
"compilerOptions": {
"baseUrl": "./modules"
}
}
現(xiàn)在導(dǎo)入moduleA
將會在./modules/moduleA
中查找。
import A from "moduleA";
有時模塊沒有直接位于baseUrl中。加載器使用映射配置在運行時去映射模塊名稱和文件,請參閱RequireJs文檔和SystemJS文檔。
TypeScript編譯器支持tsconfig
文件中使用"paths"
屬性映射的聲明。
例如,導(dǎo)入"jquery"
模塊在運行時會被轉(zhuǎn)換為"node_modules/jquery/dist/jquery.slim.min.js"
。
{
"compilerOptions": {
"baseUrl": "./node_modules",
"paths": {
"jquery": ["jquery/dist/jquery.slim.min"]
}
}
使用"paths"
也允許更復(fù)雜的映射,包括多次后退的位置。考慮一個只有一個地方的模塊是可用的,其它的模塊都在另一個地方的項目配置。
rootDirs
和虛擬目錄使用rootDirs
,你可以告知編譯器的根目錄組合這些“虛擬”目錄。因此編譯器在這些“虛擬”目錄中解析相對導(dǎo)入模塊,仿佛是合并到一個目錄中一樣。
給定的項目結(jié)構(gòu)
src
└── views
└── view1.ts (imports './template1')
└── view2.ts
generated
└── templates
└── views
└── template1.ts (imports './view2')
構(gòu)建步驟將復(fù)制/src/views
和/generated/templates/views
目錄下的文件輸出到同一個目錄中。在運行時,視圖期望它的模板和它存在同一目錄中,因此應(yīng)該使用相對名稱"./template"
導(dǎo)入。
"rootDir"
指定的一組根目錄的內(nèi)容將會在運行時合并。因此在我們的例子,tsconfig.json
文件應(yīng)該類似于:
{
"compilerOptions": {
"rootDirs": [
"src/views",
"generated/templates/views"
]
}
}
--traceResolution
提供了一種方便的方法,以了解模塊如何被編譯器解析的。
tsc --traceResolution
當你使用一個新模塊時,如果不想要花費時間書寫一個聲明時,現(xiàn)在你可以使用快捷聲明以便以快速開始。
declare module "hot-new-module";
所有從快捷模塊的導(dǎo)入都具有任意類型。
import x, {y} from "hot-new-module";
x(y);
以前使用模塊加載器(例如AMD和SystemJS)導(dǎo)入沒有代碼的資源是不容易的。之前,必須為每個資源定義一個外部模塊聲明。
TypeScript 2.0支持使用通配符符號(*
)定義一類模塊名稱。這種方式,一個聲明只需要一次擴展名,而不再是每一個資源。
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;
}
現(xiàn)在你可以導(dǎo)入匹配"*!text"
或"json!*"
的東西了。
import fileContent from "./xyz.txt!text";
import data from "json!http://example.com/data.json";
console.log(data, fileContent);
當從一個基于非類型化的代碼遷移時,通配符模塊的名稱可能更加有用。結(jié)合快捷外部模塊聲明,一組模塊可以很容易地聲明為any
。
declare module "myLibrary/*";
所有位于myLibrary
目錄之下的模塊的導(dǎo)入都被編譯器認為是any
類型,因此這些模塊的任何類型檢查都會被關(guān)閉。
import { readFile } from "myLibrary/fileSystem/readFile`;
readFile(); // readFile是'any'類型
一些庫被設(shè)計為可以使用多種模塊加載器或者不是使用模塊加載器(全局變量)來使用,這被稱為UMD或同構(gòu)模塊。這些庫可以通過導(dǎo)入或全局變量訪問。
舉例:
export const isPrime(x: number): boolean;
export as namespace mathLib;
然后,該庫可作為模塊導(dǎo)入使用:
import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // 錯誤:無法在模塊內(nèi)部使用全局定義
它也可以被用來作為一個全局變量,只限于沒有import
和export
腳本文件中。
mathLib.isPrime(2);
現(xiàn)在可以在類中聲明可選屬性和方法,與接口類似。
class Bar {
a: number;
b?: number;
f() {
return 1;
}
g?(): number; // 可選方法的方法體可以省略
h?() {
return 2;
}
}
在--strictNullChecks
模式下編譯時,可選屬性和方法會自動添加undefined
到它們的類型中。因此,上面的b
屬性類型是number | undefined
,上面g
方法的類型是(()=> number) | undefined
。使用類型保護可以去除undefined
。
類的構(gòu)造函數(shù)可以被標記為private
或protected
。私有構(gòu)造函數(shù)的類不能在類的外部實例化,并且也不能被繼承。受保護構(gòu)造函數(shù)的類不能再類的外部實例化,但是可以被繼承。
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的構(gòu)造函數(shù)是私有的。
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;
}
如果對象字面量中所有已知的屬性是賦值給索引簽名,那么現(xiàn)在對象字面量類型可以賦值給索引簽名類型。這使得一個使用對象字面量初始化的變量作為參數(shù)傳遞給期望參數(shù)是map或dictionary的函數(shù)成為可能:
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); // 現(xiàn)在可以,以前不可以。
--lib
編譯參數(shù)包含內(nèi)置類型聲明獲取ES6/ES2015內(nèi)置API聲明僅限于target: ES6
。輸入--lib
,你可以使用--lib
指定一組項目所需要的內(nèi)置API。比如說,如果你希望項目運行時支持Map
、Set
和Promise
(例如現(xiàn)在靜默更新瀏覽器),直接寫--lib es2015.collection,es2015.promise
就好了。同樣,你也可以排除項目中不需要的聲明,例如在node項目中使用--lib es5,es6
排除DOM。
下面是列出了可用的API:
tsc --target es5 --lib es5,es2015.promise
"compilerOptions": {
"lib": ["es5", "es2015.promise"]
}
--noUnusedParameters
和--noUnusedLocals
標記未使用的聲明TypeScript 2.0有兩個新的編譯參數(shù)來幫助你保持一個干凈的代碼庫。-noUnusedParameters
編譯參數(shù)標記所有未使用的函數(shù)或方法的參數(shù)錯誤。--noUnusedLocals
標記所有未使用的局部(未導(dǎo)出)聲明像變量、函數(shù)、類和導(dǎo)入等等,另外未使用的私有類成員在--noUnusedLocals
作用下也會標記為錯誤。
import B, { readFile } from "./b";
// ^ 錯誤:`B`聲明了,但是沒有使用。
readFile();
export function write(message: string, args: string[]) {
// ^^^^ 錯誤:'arg'聲明了,但是沒有使用。
console.log(message);
}
使用以_
開頭命名的參數(shù)聲明不會被未使用參數(shù)檢查。例如:
function returnNull(_a) { // 正確
return null;
}
.js
擴展名TypeScript 2.0之前,模塊名稱總是被認為是沒有擴展名的。例如,導(dǎo)入一個模塊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
同時使用之前編譯參數(shù)target : es5
和module: es6
同時使用被認為是無效的,但是現(xiàn)在是有效的。這將有助于使用基于ES2015的tree-shaking(將無用代碼移除)比如 rollup。
現(xiàn)在函數(shù)形參和實參列表末尾允許有逗號。這是對第三階段的ECMAScript提案的實現(xiàn), 并且會編譯為可用的 ES3/ES5/ES6。
function foo(
bar: Bar,
baz: Baz, // 形參列表末尾添加逗號是沒有問題的。
) {
// 具體實現(xiàn)……
}
foo(
bar,
baz, // 實參列表末尾添加逗號同樣沒有問題
);
--skipLibCheck
TypeScript 2.0添加了一個新的編譯參數(shù)--skipLibCheck
,該參數(shù)可以跳過聲明文件(以.d.ts
為擴展名的文件)的類型檢查。當一個程序包含有大量的聲明文件時,編譯器需要花費大量時間對已知不包含錯誤的聲明進行類型檢查,通過跳過聲明文件的類型檢查,編譯時間可能會大大縮短。
由于一個文件中的聲明可以影響其他文件中的類型檢查,當指定--skipLibCheck
時,一些錯誤可能檢測不到。比如說, 如果一個非聲明文件中的類型被聲明文件用到, 可能僅在聲明文件被檢查時能發(fā)現(xiàn)錯誤. 不過這種情況在實際使用中并不常見。
這是重復(fù)定義錯誤的一個常見來源。多個聲明文件定義相同的接口成員。
TypeScript 2.0放寬了這一約束,并允許可以不同代碼塊中出現(xiàn)重復(fù)的標識符, 只要它們有完全相同的類型。
在同一代碼塊重復(fù)定義仍不允許。
interface Error {
stack?: string;
}
interface Error {
code?: string;
path?: string;
stack?: string; // OK
}
--declarationDir
--declarationDir
可以使生成的聲明文件和JavaScript文件不在同一個位置中。
更多建議: