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文件聲明全局類型
步驟:
  1. 創建.d.ts文件(如src/types/global.d.ts);
  2. 直接聲明類型(無需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;

三、最佳實踐與常見問題

  1. 配置生效範圍
  • 確保tsconfig.json包含聲明文件路徑:
   "include": ["src//.ts", "src//.d.ts", "src//*.vue"] // 包含聲明文件[citation:3][citation:9]
  1. 避免全局污染
  • 非全局類型應使用模塊導出(export),避免濫用全局聲明
  1. interface vs type
  • 優先用interface:支持聲明合併(如擴展Vue類型);
  • 複雜聯合類型用type(如type Status = "success" | "error")。
  1. 錯誤處理
  • 類型未生效:檢查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'; // 聲明全局類型
}