淺析Typescript類型聲明文件定義、為什么需要聲明文件、如何編寫TS聲明文件(如何自定義類型聲明文件、如何給第三方庫寫聲明文件)


一、為什么需要聲明文件

1、創建 src/sum/index.js 文件,內容如下: 這是一個最普通不過的 js 文件,對外暴露 sum() 方法,在 nodejs 中運行。

function sum(a, b) { return a + b } module.exports = sum

2、創建 src/index.ts 文件,內容如下: (這是一個 ts 文件,在 ts 文件中導入 js 文件)

import sum from './sum' console.log(sum(2, 2))

  這時,如果使用 Vscode 編輯代碼,應該可以看到如下的報錯:意思就是沒找到 sum 文件的聲明文件。

3、為什么會報這個錯誤?

  typescript 編譯器看到的每個變量、方法都必須明確知道它的類型,在 src/index.ts 文件中導入 src/sum/index.js 文件,js 文件中的方法是沒有類型的,造成 typescript 不能識別的錯誤。

  解決方法也很簡單,編輯 tsconfig.json 文件:

"allowJs": true, "outDir": "./dist", "rootDir": "./src",

  其中 allowJs 配置告訴 typescript 編輯器將 js 文件中的所有變量和方法都設置 any 類型,這樣 typescript 編譯器就能識別 js 文件了。

  添加配置后報錯消失,鼠標移動到 sum() 方法可以看到方法參數確確實實都設置為 any 類型了。

// 此時目錄結構應該如下:
|-- test-declare |-- src |-- sum |-- index.js |-- index.ts |-- package.json |-- tsconfig.json

4、編譯代碼

  打開cmd,編譯代碼,編譯完成后根目錄下會生成 dist 目錄。

npx tsc -w

5、啟動程序

  另外打開一個cmd,運行程序,可以看到打印出計算結果。

node dist/index.js 4

  雖然 ts 文件中可以導入 js 文件,並正常運行程序,但是,js 文件的方法類型全是 any 很惡心。我們希望為 js 文件里的變量和方法添加真實的類型,這就需要定義聲明文件。

二、定義類型聲明文件

1、創建 src/sum/index.d.ts 文件,內容如下:

declare function sum(a: number, b: number): number export default sum

  此時再查看 src/index.ts 文件,可以看到導入的 sum() 方法的參數已經有類型提示了

// 此時目錄結構為:
|-- test-declare |-- src |-- sum |-- index.js |-- index.d.ts      // 類型聲明文件
        |-- index.ts |-- package.json |-- tsconfig.json

三、給第三方庫寫聲明文件

  很多第三方庫是用 js 寫的,通過設置 allowJs: true 配置可以在 typescript 工程使用這些庫,但是沒法知道庫里面變量的類型以及方法參數的類型,很不友好。

  我們期待:在 Vscode 開發時,只要敲出方法,編輯器可以自行提示該方法參數的類型是什么,這樣我就不會把原本該寫成數值類型的參數寫成字符串類型了,大大降低代碼出錯風險。

1、如果你是第三方庫作者

  如果您是第三方庫的作者,我們希望您在自己的庫里就添加上聲明文件。

  手動創建 node_modules/subtract 模擬第三方庫,切換到 subtract 目錄下執行 $ npm init -y 初始化 subtract 工程。

|-- test-declare |-- node_modules   // 手動創建 subtract 模擬第三方庫 
        |-- subtract |-- src |-- index.js |-- index.d.ts |-- package.json |-- src |-- ....
// 編輯 node_modules/subtract/src/index.js 文件,內容如下:
function subtract(a, b) { return a - b } module.exports = subtract // 編輯 node_modules/subtract/index.d.js 文件,內容如下:
declare function subtract(a: number, b: number): number export default subtract // 修改 package.json 文件,其中 types 指向聲明文件路徑。
"main": "./src/index.js", "types": "./index.d.ts",

實測發現,外部庫找第三方庫聲明文件默認路徑為第三方庫(subtract)根目錄下的 index.d.ts 文件,找不到的話,會去找第三方庫 package.json 中 types 字段中設置的路徑。

  編輯 src/index.ts 文件,導入 subtract 庫並執行方法,鼠標移動到 subtract() 方法上,可以看到也是有參數類型提示的,測試成功。

2、如果你是第三方庫的使用者

  如果您是第三方庫的使用者,您是沒法直接修改第三方庫的源碼,只能改自己的代碼。

// 手動創建 node_modules/multiply 模擬第三方庫, // 切換到 multiply 目錄下執行 $ npm init -y 初始化 multiply 工程。
|-- test-declare |-- node_modules   // 手動創建 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 文件,導入 multiply 模塊,可以看到報錯:沒有找到 multiply 模塊的聲明文件。

  報錯信息也提供了兩種解決方案:

(1)npm install @types/multiply 這種方案前提是有人已經寫好了聲明文件,我們可以直接安裝下就可以了;

(2)add a new declaration(.d.ts) file containing "declare module multiply" 如果沒有 @types/multiply 包,還可以在根目錄下新建 global.d.ts,內容寫上 declare module 'multiply'。這樣做只能保證代碼不報錯,但是鼠標移動到 multiply 上面是沒有參數類型提示的,這明顯不是我們想要的。

  那么我們該怎樣做呢?

  創建 test-declare/types/multiply/index.d.ts 文件寫聲明文件,types 下目錄的名字一定要和第三方庫的名字一毛一樣,這里為第三方庫 multiply 寫聲明文件,因此創建 types/multiply 目錄。

declare function multiply(a: number, b: number): number export default multiply

  編輯 tsconfig.json 文件,告訴 typescirpt 去哪里找我們自己定義的聲明文件。

"baseUrl": "./", "paths": { "*": [ "types/*" ] }, 

  回過頭看下 src/index.ts 文件,multiply() 方法的參數類型已經可以顯示了

// 此時目錄結構為:
|-- test-declare |-- ... |-- src |-- types |-- multiply |-- index.d.ts       // 三方庫的聲明文件
    |-- ....

四、聲明文件深入理解

1、聲明文件的定義

  通俗地來講,在 TypeScript 中以 .d.ts 為后綴的文件,我們稱之為 TypeScript 聲明文件。它的主要作用是描述 JavaScript 模塊內所有導出接口的類型信息。

2、什么時候需要寫 TS 聲明文件?

  在日常的開發中,絕大多數時候是不需要我們單獨去編寫一個 TS 聲明文件的。如果我們的文件本身是用 TS 編寫的,在編譯的時候讓 TS 自動生成聲明文件,並在發布的時候將 .d.ts 文件一起發布即可。

  總結了以下三種情況,需要我們手動定義聲明文件:

(1)通過 script 標簽引入的第三方庫

  一些通過 CDN 引入的小工具包,掛載了一些全局的方法,如果在 TS 中直接使用的話,會報 TS 語法錯誤,這時候就需要我們對這些全局的方法進行 TS 聲明。

(2)使用的第三方 npm 包,但是沒有提供聲明文件

  第三方 npm 包如果有提供聲明文件的話,一般會以兩種形式存在:一是 @types/xxx,另外是在源代碼中提供 .d.ts 聲明文件。第一種的話一般是一些使用量比較高的庫會提供,可以通過 npm i @type/xxx 嘗試安裝。如果這兩種都不存在的話,那就需要我們自己來定義了。

(3)自身團隊內比較優秀的 JS 庫或插件,為了提升開發體驗

3、如何讓 TS 在編譯時自動生成 .d.ts 文件呢?只需要在 tsconfig.json 配置文件中開啟即可,TS 編譯時就會自動生成 .d.ts 聲明文件

{ "compilerOptions": { "declaration": true } }

五、如何編寫 TS 聲明文件

  對於不同形式的聲明文件,寫法上會有一定的差異。這里需要特別注意一點的是:聲明文件中只是對類型的定義,不能進行賦值

1、全局變量

  全局變量的聲明文件主要有以下幾種語法:

declare let/const  // 聲明全局變量
declare function   // 聲明全局方法
declare class      // 聲明全局類
declare enum       // 聲明全局枚舉類型 
declare namespace  // 聲明(含有子屬性的)全局對象
interface/type     // 聲明全局類型

  這里需要注意的是只是定義類型,不能進行賦值。

// 變量
declare let userName: string; declare const wx: any; // 函數、函數重載
declare function getName(uid: number): string; declare function getName(): string; declare function getName(cb: () => any): any; //
declare class Course { cid: number; constructor(cid){}; getCoursePrice(): number; } // 枚舉
declare enum Status { Loading, Success, Failed, } // 接口 interface declare 可以不需要
interface CourseInfo { cid: number; name: string; } interface CGIData<T> { data: T; retcode: 0; } // 命名空間
declare namespace User { // 局部 Test.User
  interface User { name: string; age: number; } function getUserInfo(name: string): User { return ""; } namespace fn { function extend(obj: any): any; } } // 聲明合並
declare function User(id: number): string;

2、npm 包

  對於沒有提供聲明文件的 npm 包,我們可以創建一個 types 目錄,來管理自己寫的聲明文件,同時需要在配置文件 tsconfig.json 中的 paths 和 basrUrl 中配置:

{ "compilerOptions": { "module": "commonjs", "baseUrl": "./", // types文件夾的相對路徑
    "paths": { "*": ["types/*"]} } }

3、拓展原有模塊或全局變量

  對於已經有聲明定義的模塊或者全局變量,可以利用 TS 中的聲明合並對其進行拓展。

// 比如在 window 下掛載的一些全局變量:
interface Window { readonly request?: any; readonly devToolsExtension?: any; readonly wx?: any; } // 對已有模塊進行拓展:
declare module "querystring" { function escape(str: string): string; function unescape(str: string): string; } // 還可以使用三斜線的方式對聲明文件進行引用:
/// <reference path=”custom.d.ts" />

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM