TypeScript聲明文件的語法與場景詳解_第1頁
TypeScript聲明文件的語法與場景詳解_第2頁
TypeScript聲明文件的語法與場景詳解_第3頁
TypeScript聲明文件的語法與場景詳解_第4頁
TypeScript聲明文件的語法與場景詳解_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第TypeScript聲明文件的語法與場景詳解目錄簡介語法內(nèi)容模塊化模塊語法三斜線指令referenceamd-module場景1.在內(nèi)部項目中給內(nèi)部項目寫聲明文件2.給第三方包寫聲明文件全局變量的第三方庫修改全局變量的模塊的第三方庫的聲明修改windowESM和CommonJSUMD模塊插件總結(jié)

簡介

聲明文件是以.d.ts為后綴的文件,開發(fā)者在聲明文件中編寫類型聲明,TypeScript根據(jù)聲明文件的內(nèi)容進行類型檢查。(注意同目錄下最好不要有同名的.ts文件和.d.ts,例如lib.ts和lib.d.ts,否則模塊系統(tǒng)無法只根據(jù)文件名加載模塊)

為什么需要聲明文件呢?我們知道TypeScript根據(jù)類型聲明進行類型檢查,但有些情況可能沒有類型聲明:

第三方包,因為第三方包打包后都是JavaScript語法,而非TypeScript,沒有類型。宿主環(huán)境擴展,如一些hybrid環(huán)境,在window變量下有一些bridge接口,這些接口沒有類型聲明。

如果沒有類型聲明,在使用變量、調(diào)用函數(shù)、實例化類的時候就沒法通過TypeScript的類型檢查。

聲明文件就是針對這些情況,開發(fā)者在聲明文件中編寫第三方模塊的類型聲明/宿主環(huán)境的類型聲明。讓TypeScript可以正常地進行類型檢查。

除此之外,聲明文件也可以被導(dǎo)入,使用其中暴露的類型定義。

總之,聲明文件有兩種用法:

被通過import導(dǎo)入,使用其中暴露的類型定義和變量聲明。和相關(guān)模塊關(guān)聯(lián),為模塊進行類型聲明。

對于第二種用法,聲明文件如何同相關(guān)模塊關(guān)聯(lián)呢?

比如有個第三方包名字叫foo,那么TypeScript會在node_modules/foo中根據(jù)其package.json的types和typing字段查找聲明文件查找到的聲明文件被作為該模塊的聲明文件;TypeScript也會在node_modules/@types/foo/目錄中查找聲明文件,如果能找到就被作為foo模塊的聲明文件;TypeScript還會在我們的項目中查找.d.ts文件,如果遇到declaremodulefoo語句,則該聲明被用作foo模塊的聲明。

總結(jié)一下,TypeScript會在特定的目錄讀取指定的聲明文件。

在內(nèi)部項目中,TypeScript會讀取tsconfig.json中的文件集合,在其中的聲明文件才會被處理。讀取node_modules中各第三方包的package.json的types或者typing指定的文件。讀取@types目錄下同名包的聲明文件。

聲明文件中的代碼不會出現(xiàn)在最終的編譯結(jié)果中,編譯后會把轉(zhuǎn)換后的JavaScript代碼輸出到outDir選項指定的目錄中,并且把.ts模塊中使用到的值的聲明都輸出到declarationDir指定的目錄中。

而在.ts文件中的聲明語句,編譯后會被去掉,如

declareleta:number;

exportdefaulta;

會被編譯為

"usestrict";

exports.__esModule=true;

exports["default"]=a;

TypeScript編譯過程不僅將TypeScript語法轉(zhuǎn)譯為ES6/ES5,還會將代碼中.ts文件中用到的值的類型輸出到指定的聲明文件中。如果你需要實現(xiàn)一個庫項目,這個功能很有用,因為用到你的庫的項目可以直接使用這些聲明文件,而不需要你再為你的庫寫聲明文件。

語法

內(nèi)容

TypeScript中的聲明會創(chuàng)建以下三種實體之一:命名空間,類型或值。

命名空間最終被編譯為全局變量,因此我們也可以認為聲明文件中其實創(chuàng)建了類型和值兩種實體。即定義類型或者聲明值。

//類型接口

interfacePerson{name:string;}

//類型類型別名

typeFruit={size:number};

//值變量

declareleta:number;

//值函數(shù)

declarefunctionlog(message:string):void;

//值類

declareclassPerson{name:string;}

//值枚舉

declareenumColor{Red,Green}

//值命名空間

declarenamespaceperson{letname:string;}

我們注意到類型可以直接定義,但是值的聲明需要借助declare關(guān)鍵字,這是因為如果不用declare關(guān)鍵字,值的聲明和初始化是一起的,如

leta:number;

//編譯為

vara;

但是編譯結(jié)果是會去掉所有的聲明語句,保留初始化的部分,而聲明文件中的內(nèi)容只是起聲明作用,因此需要通過declare來標(biāo)識,這只是聲明語句,編譯時候直接去掉即可。

TypeScript也約束聲明文件中聲明一個值必須要用declare,否則會被認為存在初始化的內(nèi)容,從而報錯。

//foo.d.ts

leta:number=1;//errorTS1039:Initializersarenotallowedinambientcontexts.

declare也允許出現(xiàn)在.ts文件中,但一般不會這么做,.ts文件中直接用let/const/function/class就可以聲明并初始化一個變量。并且.ts文件編譯后也會去掉declare的語句,所以不需要declare語句。

注意,declare多個同名的變量是會沖突的

declareletfoo:number;//errorTS2451:Cannotredeclareblock-scopedvariable'a'.

declareletfoo:number;//errorTS2451:Cannotredeclareblock-scopedvariable'a'.

除了使用declare聲明一個值,declare還可以用來聲明一個模塊和全局的插件,這兩種用法都是在特定場景用來給第三方包做聲明。

declaremodule用來給一個第三方模進行類型聲明,比如有一個第三方包foo,沒有類型聲明。我們可以在我們項目中實現(xiàn)一個聲明文件來讓TypeScript可以識別模塊類型:foo.d.ts

//foo.d.ts

declaremodule'foo'{

exportletsize:number;

}

然后我們就可以使用了:

importfoofrom'foo';

console.log(foo.size);

declaremodule除了可以用來給一個模塊聲明類型,還可以用來實現(xiàn)模塊插件的聲明。后面小節(jié)中會做介紹。

declareglobal用來給擴展全局的第三方包進行聲明,后面小節(jié)介紹。

模塊化

模塊語法

聲明文件的模塊化語法和.ts模塊的類似,在一些細節(jié)上稍有不同。.ts導(dǎo)出的是模塊(typescript會根據(jù)導(dǎo)出的模塊判斷類型),.d.ts導(dǎo)出的是類型的定義和聲明的值。

聲明文件可以導(dǎo)出類型,也可以導(dǎo)出值的聲明

//index.d.ts

//導(dǎo)出值聲明

exportleta:number;

//導(dǎo)出類型

exportinterfacePerson{

name:string;

};

聲明文件可以引入其他的聲明文件,甚至可以引入其他的.ts文件(因為.ts文件也可能導(dǎo)出類型)

//Person.d.ts

exportdefaultinterfacePerson{name:string}

//index.d.ts

importPersonfrom'./person';

exportletp:Person;

如果聲明文件不導(dǎo)出,默認是全局可以訪問的

//person.d.ts

interfacePerson{name:string}

declareletp:Person;

//index.ts

letp1:Person={name:'Sam'};

console.log(p);

如果使用模塊導(dǎo)出語法(ESM/CommJS/UMD),則不解析為全局(當(dāng)然UMD還是可以全局訪問)。

//ESM

interfacePerson{name:string}

exportletp:Person;

exportdefaultPerson;

//CommonJS

interfacePerson{name:string}

declareletp:Person;

export=p;

//UMD

interfacePerson{name:string}

declareletp:Person;

export=p;

exportasnamespacep;

注意:UMD包exportasnamespace語法只能在聲明文件中出現(xiàn)。

三斜線指令

聲明文件中的三斜線指令,用于控制編譯過程。

三斜線指令僅可放在包含它的文件的最頂端。

如果指定--noResove編譯選項,預(yù)編譯過程會忽略三斜線指令。

reference

reference指令用來表明聲明文件的依賴情況。

///referencepath=.../用來告訴編譯器依賴的其他聲明文件。編譯器預(yù)處理時候會將path指定的聲明文件加入進來。路徑是相對于文件自身的。引用不存在的文件或者引用自身,會報錯。

///referencetypes=node/用來告訴編譯器它依賴node_modules/@types/node/index.d.ts。如果你的項目里面依賴了@types中的某些聲明文件,那么編譯后輸出的聲明文件中會自動加上這個指令,用以說明你的項目中的聲明文件依賴了@types中相關(guān)的聲明文件。

///referenceno-default-lib=true/,

這涉及兩個編譯選項,--noLib,設(shè)置了這個編譯選項后,編譯器會忽略默認庫,默認庫是在安裝TypeScript時候自動引入的,這個文件包含JavaScript運行時(如window)以及DOM中存在各種常見的環(huán)境聲明。但是如果你的項目運行環(huán)境和基于標(biāo)準(zhǔn)瀏覽器運行時環(huán)境有很大不同,可能需要排除默認庫,一旦你排除了默認的lib.d.ts文件,你就可以在編譯上下文中包含一個命名相似的文件,TypeScript將提取該文件進行類型檢查。

另一個編譯選項是--skipDefaultLibCheck這個選項會讓編譯器忽略包含了///referenceno-default-lib=true/指令的聲明文件。你會注意到在默認庫的頂端都會有這個三斜線指令,因此如果采用了--skipDefaultLibCheck編譯選項,也同樣會忽略默認庫。

amd-module

amd-module相關(guān)指令用于控制打包到amd模塊的編譯過程

///amd-modulename=NamedModule/這個指令用于告訴編譯器給打包為AMD的模塊傳入模塊名(默認情況是匿名的)

///amd-modulename='NamedModule'/

exportclassC{

}

編譯結(jié)果為

define("NamedModule",["require","exports"],function(require,exports){

varC=(function(){

functionC(){

returnC;

})();

exports.C=C;

});

場景

這里我們將自己的項目代碼稱為內(nèi)部項目,引入的第三方模塊,包括npm引入的和script引入的,稱為外部模塊。

1.在內(nèi)部項目中給內(nèi)部項目寫聲明文件

自己項目中,給自己的模塊寫聲明文件,例如多個模塊共享的類型,就可以寫一個聲明文件。這種場景通常不必要,一般是某個.ts文件導(dǎo)出聲明,其他模塊引用聲明。

2.給第三方包寫聲明文件

給第三方包寫聲明文件又分為在內(nèi)部項目中給第三方包寫聲明文件和在外部模塊中給外部模塊寫聲明文件。

在內(nèi)部項目中給第三方包寫聲明文件:如果第三方包沒有TS聲明文件,則為了保證使用第三方包時候能夠通過類型檢查,也為了安全地使用第三方包,需要在內(nèi)部項目中寫第三方包的聲明文件。

在外部模塊中給外部模塊寫聲明文件:如果你是第三方庫的作者,無論你是否使用TypeScript開發(fā)庫,都應(yīng)該提供聲明文件以便用TypeScript開發(fā)的項目能夠更好地使用你的庫,那么你就需要寫好你的聲明文件。

這兩種情況的聲明文件的語法類似,只在個別聲明語法和文件的處理上有區(qū)別:

內(nèi)部項目給第三方包寫聲明文件時候,以.d.ts命名即可,然后在tsconfig.json中的files和include中配置能夠包含到文件即可,外部模塊的聲明文件需要打包到輸出目錄,并且在package.json中的type字段指定聲明文件位置;或者上傳到@types/moduleName中,使用者通過npminstall@types/moduleName安裝聲明文件。redux就在tsconfig.json中指定了declarationDir為./types,TypeScript會將項目的聲明都打包到這個目錄下,目錄結(jié)構(gòu)和源碼一樣,然后redux源碼入口處導(dǎo)出了所有的模塊,因此types目錄下也有一個入口的聲明文件index.d.ts,并且包含了所有的導(dǎo)出模塊聲明,redux在package.json中指定types字段(或者typings字段)為入口的聲明文件:./types/index.d.ts。這樣就實現(xiàn)了自動生成接口的聲明文件。內(nèi)部項目給第三方寫聲明文件時候,如果是通過npm模塊引入方式,如importmoduleNamefrompath則需要通過declaremodulemoduleName語法來聲明模塊。而外部模塊的聲明文件都是正常的類型導(dǎo)出語法(如exportdefaultexport=等),如果聲明文件在@types中,會將與模塊同名的聲明文件作為模塊的類型聲明;如果聲明文件在第三方包中,那么就TypeScript模塊就將它作為這個第三方包模塊的模塊聲明,當(dāng)使用者導(dǎo)入并使用這個模塊時候,TypeScript就根據(jù)相應(yīng)地聲明文件進行類型提示和類型檢查。

根據(jù)第三方包類型可以分成幾種

全局變量的第三方庫

我們知道如果不使用模塊導(dǎo)出語法,聲明文件默認的聲明都是全局的。

declarenamespaceperson{

letname:string

}

或者

interfacePerson{

name:string;

declareletperson:Person;

使用:

console.log();

修改全局變量的模塊的第三方庫的聲明

如果有第三方包修改了一個全局模塊(這個第三方包是這個全局模塊的插件),這個第三方包的聲明文件根據(jù)全局模塊的聲明,有不同的聲明方式

如果全局模塊使用命名空間聲明

declarenamespaceperson{

letname:string

}

根據(jù)命名空間的聲明合并原理,插件模塊可以這樣聲明

declarenamespaceperson{

//擴展了age屬性

letage:number;

}

如果全局模塊使用全局變量聲明

interfacePerson{

name:string;

declareletperson:Person;

根據(jù)接口的聲明合并原理,插件模塊可以這樣聲明

interfacePerson{

//擴展了age屬性

age:number;

}

上面的全局模塊的插件模塊的聲明方式可以應(yīng)用于下面的場景:

內(nèi)部項目使用了插件,但插件沒有聲明文件,我們可以在內(nèi)部項目中自己實現(xiàn)聲明文件。給插件模塊寫聲明文件并發(fā)布到@types。

如果是插件模塊的作者,希望在項目中引用全局模塊并且將擴展的類型輸出到聲明文件,以便其他項目使用??梢赃@樣實現(xiàn)

//plugin/index.ts

//注意這樣聲明才會讓TypeScript將類型輸出聲明文件

declareglobal{

//假設(shè)全局模塊使用全局變量的方式聲明

interfacePerson{

age:number

console.log(person.age);

export{};

注意,declareglobal寫在聲明文件中也可以,但是要在尾部加上export{}或者其他的模塊導(dǎo)出語句,否則會報錯。另外declareglobal在聲明文件中寫的話,編譯后不會輸出到聲明文件中。

修改window

window的類型是interfaceWindow{...},在默認庫中聲明,如果要擴展window變量(如一些hybrid環(huán)境)可以這樣實現(xiàn)

//window.d.ts

//聲明合并

interfaceWindow{

bridge:{log():void}

//或者

declareglobal{

interfaceWindow{

bridge:{log():void}

}

或者

//index.ts

declareglobal{

interfaceWindow{

bridge:{log():void}

window.bridge={log(){}}

export{};

ESM和CommonJS

給第三方的ESM或者CommonJS模塊寫聲明文件,使用ESM導(dǎo)出或者CommonJS模塊語法導(dǎo)出都可以,不管第三方包是哪種模塊形式。

看下面示例

interfacePerson{

name:string;

declareletperson:Person;

export=person;

//也可以使用exportdefaultperson;

importpersonfrom'person';

console.log();

上面的聲明文件是放在node_modules/@types/person/index.d.ts中,或者放在node_modules/person/package.json的types或者typings字段指定的位置。

如果在自己項目中聲明,應(yīng)該使用declaremodule實現(xiàn)

declaremodule'person'{

exportletname:string;

}

UMD

UMD模塊,在CommonJS聲明的基礎(chǔ)上加上exportasnamespaceModuleName;語句即可。

看下面的ESM的例子

//node_modules/@types/person/index.d.ts

interfacePerson{

name:string;

declareletperson:Person;

exportdefaultperson;

exportasnamespaceperson;

可以通過import導(dǎo)入來訪問

/

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論