記錄---xx.d.ts文件有什么用,為什么不引入都能生效?
????? 寫在開頭
點(diǎn)贊 + 收藏 === 學(xué)會(huì)??????
背景簡(jiǎn)介
在前端項(xiàng)目開發(fā)中,我們常常會(huì)遇到這樣一種情況:項(xiàng)目中引入了某個(gè)第三方庫(kù),但它沒(méi)有提供內(nèi)置的 TypeScript 類型聲明。此時(shí),如果你在 TypeScript 項(xiàng)目中直接使用這個(gè)庫(kù),編譯器就會(huì)報(bào)錯(cuò)。

也許你很聰明,知道在項(xiàng)目中的shims-vue.d.ts中通過(guò)declare聲明此模塊,來(lái)解決報(bào)錯(cuò)。

但你是否想過(guò)這些問(wèn)題:
- 為什么在
.shims-vue.d.ts文件中寫一個(gè)declare聲明就能解決報(bào)錯(cuò)? - .d.ts文件明明沒(méi)有顯示引入,為什么就生效了?
- 任意xxx.d.ts文件聲明為什么都能發(fā)揮作用嗎?
其實(shí),能夠?qū)懸恍?declare module 'xxx' 就讓 TypeScript 編譯器“閉嘴”,看似簡(jiǎn)單,背后卻隱藏著 TypeScript 類型系統(tǒng)的一些核心機(jī)制。
.d.ts 文件的作用
.d.ts 文件是 TypeScript 世界中的“翻譯器”,它不負(fù)責(zé)運(yùn)行代碼,而是負(fù)責(zé)描述代碼的結(jié)構(gòu)、類型、接口、模塊,使得 TypeScript 編譯器“明白”你在干什么,從而讓類型檢查、提示、自動(dòng)補(bǔ)全等功能得以正常運(yùn)作。
- 為 JavaScript 代碼或第三方庫(kù)補(bǔ)充類型
當(dāng)你引入一個(gè) 沒(méi)有類型定義 的庫(kù)時(shí),比如老舊的 JS 庫(kù)或某些 npm 包沒(méi)有內(nèi)置 TypeScript 類型,會(huì)導(dǎo)致 TS 編譯器報(bào)錯(cuò)。這時(shí)你可以寫一個(gè) .d.ts 文件,手動(dòng)聲明它的類型:
// types/jquery.d.ts declare var $: any;
- 為非代碼資源聲明模塊(如 SVG、CSS、JSON 等)
在項(xiàng)目中引入非代碼資源時(shí),TypeScript 默認(rèn)是無(wú)法識(shí)別的,比如:
import logo from './logo.svg';
.d.ts 文件來(lái)告訴 TS 這是什么類型:// types/shims-svg.d.ts
declare module '*.svg' {
const content: string;
export default content;
}
- 定義全局變量或類型
比如 VITE_APP_VERSION 是在構(gòu)建時(shí)注入的變量,你可以這樣聲明:
// types/global.d.ts declare const VITE_APP_VERSION: string;
這樣就可以在任何文件中使用,不報(bào)錯(cuò)、還能獲得類型提示。
- 定義環(huán)境變量、全局命名空間等復(fù)雜類型結(jié)構(gòu)
例如:
interface Window {
myGlobalAPI: () => void;
}
declare namespace MyLib {
type Options = {
debug: boolean;
};
}
補(bǔ)充已有模塊的類型信息(模塊擴(kuò)展)
你可以給已有模塊添加自定義類型,不需要修改原始庫(kù)代碼:
// types/vue-router.d.ts
import 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
auth?: boolean;
}
}
為什么寫一個(gè) declare 就能解決報(bào)錯(cuò)?
TypeScript 是強(qiáng)類型語(yǔ)言,它在編譯時(shí)會(huì)嘗試為每一個(gè)變量、函數(shù)、模塊、類型標(biāo)識(shí)符“找到定義”。當(dāng)我們引入一個(gè)沒(méi)有類型聲明的第三方模塊時(shí),比如:
import something from 'vs-tree';
如果 vs-tree 沒(méi)有提供 .d.ts 文件(也就是沒(méi)有類型定義),TypeScript 編譯器就會(huì)報(bào)錯(cuò):

但當(dāng)你寫上:
// shims-vue.d.ts 或任何 .d.ts 文件 declare module 'vs-tree';
你就是手動(dòng)告訴 TypeScript:“我知道這個(gè)模塊存在,不用你擔(dān)心類型問(wèn)題。”于是 TS 編譯器不再報(bào)錯(cuò),默認(rèn)把它當(dāng)作 any 類型處理。這其實(shí)是使用 .d.ts 的一個(gè)最基礎(chǔ)場(chǎng)景:模塊聲明補(bǔ)全。
為什么 .d.ts 文件不引入也能生效?
這要從 TypeScript 的文件識(shí)別機(jī)制說(shuō)起。
TypeScript 在編譯一個(gè)項(xiàng)目時(shí),首先會(huì)加載項(xiàng)目根目錄下的 tsconfig.json,它會(huì)根據(jù)其中的配置項(xiàng)決定:
- 要包含哪些文件
- 要排除哪些文件
- 要使用哪些類型庫(kù)(如 DOM、ESNext)
- 要如何解析模塊路徑(如路徑別名)
具體來(lái)說(shuō),.d.ts 文件能自動(dòng)生效,主要有以下幾種情況:
在 tsconfig.json 的 include 范圍內(nèi)
只要你的 .d.ts 文件路徑在 include 的匹配范圍內(nèi),TS 編譯器就會(huì)自動(dòng)加載它:
{
"include": ["src", "types"]
}
如你把 shims-vue.d.ts 放在 src/ 或 types/ 下,它就會(huì)自動(dòng)生效。
被編譯器當(dāng)作“全局聲明”文件識(shí)別
.d.ts 文件中如果沒(méi)有 import/export,就會(huì)被 TypeScript 當(dāng)作“全局類型聲明文件”(Global Declaration File),自動(dòng)合并進(jìn)全局作用域。這種文件中的內(nèi)容對(duì)所有文件可見(jiàn):
// types/global.d.ts declare const __APP_VERSION__: string;
你在任意 .ts 文件中都能直接使用 __APP_VERSION__,不需要任何引入。
被放置在默認(rèn)類型目錄下(如 @types)
TypeScript 默認(rèn)會(huì)去 node_modules/@types 中找類型定義(社區(qū)維護(hù)的 DefinitelyTyped 類型庫(kù))。如果你把聲明文件放進(jìn)這個(gè)路徑,甚至可以模擬 npm 包類型的形式存在。
任意 xxx.d.ts 文件都能生效嗎?
并不是,之前已經(jīng)提到,只有在tsconfig.json中的 include中被包含,編譯器才會(huì)自動(dòng)加載。

如上圖,只有src目錄下的任意xx.d.ts才會(huì)被自動(dòng)加載。但以下情況,即使在include中聲明也不會(huì)被加載。

本文轉(zhuǎn)載于:https://juejin.cn/post/7500654211785392179
如果對(duì)您有所幫助,歡迎您點(diǎn)個(gè)關(guān)注,我會(huì)定時(shí)更新技術(shù)文檔,大家一起討論學(xué)習(xí),一起進(jìn)步。


浙公網(wǎng)安備 33010602011771號(hào)