為什么需要聲明文件
初始化項目
$ mkdir test-declare
$ cd test-declare
$ npm init -y
$ yarn add typescript -D
$ npx tsc --init
創(chuàng)建 src/sum/index.js 文件岩四,內(nèi)容如下:
這是一個最普通不過的 js 文件,對外暴露 sum() 方法哥攘,在 nodejs 中運行剖煌。
function sum(a, b) {
return a + b
}
module.exports = sum
創(chuàng)建 src/index.ts 文件,內(nèi)容如下:
(這是一個 ts 文件逝淹,在 ts 文件中導(dǎo)入 js 文件)
import sum from './sum'
console.log(sum(2, 2))
這時耕姊,如果使用 Vscode 編輯代碼,應(yīng)該可以看到如下的報錯:意思就是沒找到 sum 文件的聲明文件栅葡。
為什么會報這個錯誤茉兰?
typescript 編譯器看到的每個變量、方法都必須明確知道它的類型妥畏,在 src/index.ts 文件中導(dǎo)入 src/sum/index.js 文件邦邦,js 文件中的方法是沒有類型的,造成 typescript 不能識別的錯誤醉蚁。
解決方法也很簡單燃辖,編輯 tsconfig.json 文件:
"allowJs": true,
"outDir": "./dist",
"rootDir": "./src",
其中 allowJs 配置告訴 typescript 編輯器將 js 文件中的所有變量和方法都設(shè)置 any 類型,這樣 typescript 編譯器就能識別 js 文件了网棍。
添加配置后報錯消失黔龟,鼠標移動到 sum() 方法可以看到方法參數(shù)確確實實都設(shè)置為 any 類型了。
此時目錄結(jié)構(gòu)應(yīng)該如下:
|-- test-declare
|-- src
|-- sum
|-- index.js
|-- index.ts
|-- package.json
|-- tsconfig.json
編譯代碼
打開黑窗口滥玷,編譯代碼氏身,編譯完成后根目錄下會生成 dist 目錄。
$ npx tsc -w
啟動程序
另外打開一個黑窗口惑畴,運行程序蛋欣,可以看到打印出計算結(jié)果。
$ node dist/index.js
$ 4
雖然 ts 文件中可以導(dǎo)入 js 文件如贷,并正常運行程序陷虎,但但但但但但是,js 文件的方法類型全是 any 很惡心杠袱。
我們希望為 js 文件里的變量和方法添加真實的類型尚猿,這就需要定義聲明文件。
定義類型聲明文件
創(chuàng)建 src/sum/index.d.ts 文件楣富,內(nèi)容如下:
declare function sum(a: number, b: number): number
export default sum
此時再查看 src/index.ts 文件凿掂,可以看到導(dǎo)入的 sum() 方法的參數(shù)已經(jīng)有類型提示了。??
此時目錄結(jié)構(gòu)為:
|-- test-declare
|-- src
|-- sum
|-- index.js
|-- index.d.ts <=== 類型聲明文件
|-- index.ts
|-- package.json
|-- tsconfig.json
給第三方庫寫聲明文件
很多第三方庫是用 js 寫的纹蝴,通過設(shè)置 allowJs: true
配置可以在 typescript 工程使用這些庫庄萎,但是沒法知道庫里面變量的類型以及方法參數(shù)的類型,很不友好骗灶。
我們期待:在 Vscode 開發(fā)時惨恭,只要敲出方法,編輯器可以自行提示該方法參數(shù)的類型是什么耙旦,這樣我就不會把原本該寫成數(shù)值類型的參數(shù)寫成字符串類型了脱羡,大大降低代碼出錯風險。
如果你是第三方庫作者
如果您是第三方庫的作者免都,我們希望您在自己的庫里就添加上聲明文件锉罐。
手動創(chuàng)建 node_modules/subtract 模擬第三方庫,切換到 subtract 目錄下執(zhí)行 $ npm init -y
初始化 subtract 工程绕娘。
|-- test-declare
|-- node_modules <=== 手動創(chuàng)建 subtract 模擬第三方庫
|-- subtract
|-- src
|-- index.js
|-- index.d.ts
|-- package.json
|-- src
|-- ....
編輯 node_modules/subtract/src/index.js 文件脓规,內(nèi)容如下:
function subtract(a, b) {
return a - b
}
module.exports = subtract
編輯 node_modules/subtract/index.d.js 文件,內(nèi)容如下:
declare function subtract(a: number, b: number): number
export default subtract
修改 package.json 文件险领,其中 types 指向聲明文件路徑侨舆。
"main": "./src/index.js",
"types": "./index.d.ts",
實測發(fā)現(xiàn)秒紧,外部庫找第三方庫聲明文件默認路徑為第三方庫(subtract)根目錄下的 index.d.ts 文件,找不到的話挨下,會去找第三方庫 package.json 中 types 字段中設(shè)置的路徑熔恢。
編輯 src/index.ts 文件,導(dǎo)入 subtract 庫并執(zhí)行方法臭笆,鼠標移動到 subtract() 方法上叙淌,可以看到也是有參數(shù)類型提示的,測試成功愁铺。
如果你是第三方庫的使用者
如果您是第三方庫的使用者鹰霍,您是沒法直接修改第三方庫的源碼,只能改自己的代碼茵乱。
手動創(chuàng)建 node_modules/multiply 模擬第三方庫茂洒,切換到 multiply 目錄下執(zhí)行 $ npm init -y 初始化 multiply 工程。
|-- test-declare
|-- node_modules <=== 手動創(chuàng)建 multiply 模擬第三方庫
|-- multiply
|-- index.js
|-- package.json
|-- src
|-- ....
編輯 test-declare/node_modules/multiply/index.js 文件:
function multiply(a, b) {
return a * b
}
module.exports = multiply
修改 test-declare/src/index.ts 文件瓶竭,導(dǎo)入 multiply 模塊获黔,可以看到報錯:沒有找到 multiply 模塊的聲明文件。
報錯信息也提供了兩種解決方案:
-
npm install @types/multiply
這種方案前提是有人已經(jīng)寫好了聲明文件在验,我們可以直接安裝下就哦了玷氏; -
add a new declaration(.d.ts) file containing "declare module multiply"
如果沒有 @types/multiply 包,還可以在根目錄下新建 global.d.ts腋舌,內(nèi)容寫上declare module 'multiply'
盏触。這樣做只能保證代碼不報錯,但是鼠標移動到 multiply 上面是沒有參數(shù)類型提示的块饺,這明顯不是我們想要的赞辩。
(如果前面創(chuàng)建了 global.d.ts,刪除它)
創(chuàng)建 test-declare/types/multiply/index.d.ts 文件寫聲明文件授艰,types 下目錄的名字一定要和第三方庫的名字一毛一樣辨嗽,這里為第三方庫 multiply 寫聲明文件,因此創(chuàng)建 types/multiply 目錄淮腾。
declare function multiply(a: number, b: number): number
export default multiply
編輯 tsconfig.json 文件糟需,告訴 typescirpt 去哪里找我們自己定義的聲明文件。
"baseUrl": "./",
"paths": {
"*": [ "types/*" ]
},
回過頭看下 src/index.ts 文件谷朝,multiply() 方法的參數(shù)類型已經(jīng)可以顯示了洲押。
此時目錄結(jié)構(gòu)為:
|-- test-declare
|-- ...
|-- src
|-- types
|-- multiply
|-- index.d.ts <=== 聲明文件
|-- ....
如何寫聲明文件
還剩最后一個話題,如何編寫聲明文件圆凰,這需要掌握 Typescript 基本語法杈帐。
導(dǎo)出一個方法
上面??寫的所有聲明方法都是對外暴露一個方法,暴露變量類似。
源碼 index.js
function divide (a, b) {
return a / b
}
為 index.js 編寫聲明文件:
// index.d.ts
declare function divide(a: number, b: number): number
export default divide
導(dǎo)出一個對象字面量
想要導(dǎo)出一個對象字面量挑童,這個對象字面量內(nèi)包含了很多方法和變量累铅,如何做?
源碼 my-math.js
function multiply(a, b) {
return a * b
}
function divide(a, b) {
return a / b
}
const num1 = 4
const num2 = 2
module.exports = {
multiply, divide, num1, num2
}
使用 namespace 對外導(dǎo)出一個對象字面量站叼,對應(yīng)的聲明文件:
// index.d.ts
declare namespace obj {
function multiply(a: number, b: number): number
function divide(a: number, b: number): number
const num1: number
const num2: number
}
export default obj
使用:
// index.ts
import math from 'multiply'
console.log(math.multiply(math.num1, math.num2))