TypeScript項目中,.d.ts(類型聲明文件)和普通.ts文件兩種文件都可以定義ts類型。
不過,在功能和使用場景上有顯著區別,全局類型的聲明則需要遵循特定規範。以下是詳細解析:
一、.d.ts與普通.ts文件的區別
|
特性
|
.d.ts文件
|
普通.ts文件
|
|
核心用途
|
僅包含類型聲明(無邏輯代碼),為代碼提供類型信息
|
包含類型聲明和可執行邏輯代碼
|
|
編譯行為
|
不生成.js文件,僅用於類型檢查
|
編譯為.js文件,生成實際運行代碼
|
|
作用域
|
不默認全局生效(除非使用模塊語法export)
|
需通過import/export顯式導入導出類型
|
|
適用場景
|
- 為JS庫補充類型
- 聲明全局類型/變量
- 擴展第三方庫類型
|
- 業務邏輯實現
- 局部類型定義
|
|
關鍵字要求
|
頂級聲明需用declare(如declare const)
|
無需declare,直接定義類型或邏輯
|
示例對比:
// 普通.ts文件(含邏輯)
export const add = (a: number, b: number) => a + b;
// .d.ts文件(僅類型)
declare const add: (a: number, b: number) => number; // 無實現代碼[citation:1]
二、聲明全局可用的TypeScript類型
全局類型可在項目中任意文件直接使用,無需import。以下是常用方法:
- 通過.d.ts文件聲明全局類型
步驟:
- 創建.d.ts文件(如src/types/global.d.ts);
- 直接聲明類型(無需export)
// global.d.ts
type User = { id: string; name: string }; // 全局生效
interface Goods { price: number; stock: boolean } // 全局生效
驗證:在.vue或.ts文件中直接使用User或Goods類型
- 擴展全局命名空間(如Window)
用於在window對象上添加自定義屬性:
// global.d.ts
declare global {
interface Window {
__APP_VERSION__: string; // 擴展Window類型
}
type Theme = "light" | "dark"; // 聲明全局類型
注意:若文件含
import/export,需用declare global包裹聲明,並用export {}標記為模塊
- 為Vue擴展全局屬性
在shims-vue.d.ts中擴展Vue實例類型:
// shims-vue.d.ts
import { ComponentCustomProperties } from 'vue';
declare module 'vue' {
interface ComponentCustomProperties {
$filters: { formatCurrency: (amount: number) => string
}; // 擴展Vue實例
}
- 聲明第三方庫類型
為無類型聲明的JS庫補充類型:
// libs.d.ts
declare module "vue-drag" { // 聲明模塊類型
const drag: (el: HTMLElement) => void;
export default drag;
三、最佳實踐與常見問題
- 配置生效範圍
- 確保tsconfig.json包含聲明文件路徑:
"include": ["src//.ts", "src//.d.ts", "src//*.vue"] // 包含聲明文件[citation:3][citation:9]
- 避免全局污染
- 非全局類型應使用模塊導出(export),避免濫用全局聲明
- interface vs type
- 優先用interface:支持聲明合併(如擴展Vue類型);
- 複雜聯合類型用type(如type Status = "success" | "error")。
- 錯誤處理
- 類型未生效:檢查tsconfig.json的include配置和文件路徑;
- 重複聲明:避免在多個.d.ts中聲明同名全局類型。
總結
|
場景
|
方案
|
|
基礎全局類型(如User)
|
在.d.ts中直接聲明
|
|
擴展瀏覽器對象(如window)
|
declare global
|
|
擴展Vue實例屬性
|
ComponentCustomProperties
|
|
補充第三方庫類型
|
declare module
|
在 TypeScript 中,是否全局類型的聲明取決於文件是否被視為模塊,當文件中包含 import 或 export 語句時,文件會被視為模塊(具有局部作用域)。
因此,如果要在包含 import的文件(局部作用域模塊)中聲明全局類型或變量,必須使用 declare global 包裹聲明,並通過 export {} 標記文件為模塊,否則會因作用域衝突導致類型聲明失效。
declare global 也是唯一可以在模塊內部擴展全局作用域的方式
舉例:
// global.d.ts
import { Router } from 'vue-router'; // 含 import,文件是模塊
export {}; // 標記為模塊 ✅
declare global {
interface Window {
$router: Router; // 擴展 Window 類型
}
type Theme = 'light' | 'dark'; // 聲明全局類型
}