TypeScript從d.ts說起
TypeScript(以下簡稱TS),作為JavaScript(以下簡稱js)的一個超集,已經(jīng)深受大家的喜愛了渐北。他解決了js當中沒有類型系統(tǒng)的問題。既提供了靜態(tài)檢查,也為開發(fā)過程中帶來了代碼提示风题。
顯然我們很多項目依然是js作為主力開發(fā)的語言。那么當我們也想享受TS帶來的便利嫉父,或者當我們新的項目想使用TS無法兼容舊的js庫時沛硅。我們應該怎么做呢?
答案就是d.ts绕辖。TS為我們提供了一種方法為原本的js代碼去聲明類型摇肌,這種方法就是去編寫d.ts文件。
三種方式
對于d.ts有三種方式來使用它為我們的js代碼添加類型信息仪际。
1.在原本的js文件路徑添加同名.d.ts文件
編輯器會在你導入文件時尋找到同一路徑下的d.ts文件围小,并將你聲明的類型信息和你的js文件相對應。
優(yōu)點:簡單方便树碱。
缺點:文件多了之后不便于管理肯适。
2.在package.json當中指定types文件夾
你可以在項目的package.json當中通過types屬性指定你的類型信息路徑。編輯器依然會正確識別你導入文件的同名.d.ts文件中聲明的類型信息成榜。
優(yōu)點:集中管理不和其他文件混雜
缺點:僅適用于為自己發(fā)布的npm包有效框舔。
3.編寫專門的@types包
我們可以通過單獨為我們的包編寫另一個types包,另立一個項目。編輯器會自動從node_modules文件夾下查找@types文件夾中對應的項目來獲取類型信息刘绣。這種方式一般適用于為不在自己掌握的第三方庫添加類型信息樱溉。
優(yōu)點:能適用于第三方庫
缺點:維護成本較大
值得注意的一些問題
1.對于package的browser項無法識別。
編輯器是沒法知道你現(xiàn)在寫的文件是會用到服務端還是瀏覽器端的额港。因此如果你使用了browser項饺窿,編輯器是不會讀取到你寫在同一目錄下的同名d.ts文件。只能通過在main配置項的同一目錄下同名文件同時聲明兩個文件中的類型移斩。
2.方法入?yún)⑹且粋€對象肚医。
當方法的入?yún)⑹且粋€對象的時候,通常我們可能會把他聲明成一個接口或類型向瓷。但是這樣的話肠套,當代碼提示的時候只會提示到你的參數(shù)屬于某一個類型,而不會提示出這個類型具體有哪些參數(shù)猖任。因此你稚,建議如果這個對象不是過分復雜,可以直接將他寫在入?yún)⒗铩?/p>
declare interface dataParams {
method: 'GET' | 'POST',
action?: string,
qs?: object,
form?: object,
restfulParams?: object,
json?: object,
body?: object | string,
req?: object,
headers?: object,
}
/**
* 請求
* @param params 參數(shù)
*/
declare function isomorphicData(params: dataParams): Promise<Object>;
// 推薦做法
/**
* 請求
* @param params 參數(shù)
*/
declare function isomorphicData(params: {
method: 'GET' | 'POST',
action?: string,
qs?: object,
form?: object,
restfulParams?: object,
json?: object,
body?: object | string,
req?: object,
headers?: object,
}): Promise<Object>;
3.聲明合并
在js當中朱躺,我們時常會在聲明了一個方法之后再為這個方法添加一些屬性和方法刁赖。而在TS聲明當中,方法并不能為其聲明屬性或方法长搀。因此我們需要使用聲明合并的方式來為其添加聲明宇弛。
//js代碼
async function isomorphicData(method = 'GET') {
...
return data;
}
isomorphicData.setDirname = (dirname) => {
config.actionDirname = dirname;
};
// d.ts代碼
/**
* 請求
* @param params 參數(shù)
*/
declare function isomorphicData(params: {
method: 'GET' | 'POST',
}): Promise<Object>;
declare namespace isomorphicData {
/**
* 設置數(shù)據(jù)處理程序目錄,默認為projectDir / data
* 已棄用源请,請改用init
* @param dirname 請求配置所在路徑
*/
function setDirname(dirname: string): void;
}
值得注意的是并不是所有的類型都支持合并聲明枪芒。
4.泛型系統(tǒng)
其實熟悉其他有類型的語言的同學,應該對泛型系統(tǒng)很熟悉了谁尸。泛型其實本質(zhì)上就是一種多態(tài)舅踪。
現(xiàn)在我們有一個函數(shù),接受一個參數(shù)良蛮,返回一個參數(shù)抽碌。在不用多態(tài)的方式下我們可能會寫成:
declare function identity(arg:any):any
這樣子我們就丟失了它輸入的類型就是他返回的類型的信息,那么我們也可以通過重載來寫全背镇。
declare function identity(arg:number):number
declare function identity(arg:Function):Function
declare function identity(arg:String):String
...
但是這樣很啰嗦咬展,而且也不可能寫全所有類型。因此我們還是需要用到泛型瞒斩。
declare function identity<T>(arg:T):T
這里聲明了一個T的泛型,接受一個T類型的arg涮总,返回一個T類型的值胸囱。當你調(diào)用這個方法時,不需要主動去說明T泛型的具體類型瀑梗。TS會根據(jù)arg的值來做類型推斷烹笔。
4.類型兼容
對于d.ts的類型文件來講裳扯,如果我們只是使用在js當中來提供類型提示的話,類型兼容并不是很重要谤职。因為js并不會對他進行類型檢查饰豺。但是在TS當中使用第三方包時的d.ts類型文件就非常重要了。
首先是可選屬性:對于一些類型可能并不是所有屬性都是必須的允蜈。所以我們可以通過?設置可選屬性來通過類型判斷冤吨。
declare interface cat {
eyes:String,
name?:String
}