返回 导航

其他

hangge.com

TypeScript - 类型声明教程(declare、.d.ts文件、声明文件编写)

作者:hangge | 2026-08-15 10:56
        在 TypeScript 开发中,我们经常需要为 JavaScript 库或全局变量添加类型支持。这时就需要用到类型声明(Declaration)。类型声明文件以 .d.ts 为扩展名(ddeclare 的缩写),用于声明变量、函数、类、模块等的类型信息。它只包含类型声明,不包含具体实现,编译后也不会生成 JavaScript 代码。本文将详细介绍如何编写和使用类型声明文件。

一、基本介绍

1,什么是声明文件

(1).d.ts 文件TypeScript 的声明文件,用于描述 JavaScript 代码的类型信息。它不包含可执行代码,只包含类型声明。
提示:声明文件类似于 C/C++ 中的头文件(.h),用于描述接口规范,而不包含具体实现。

(2)声明文件的作用:
  • JavaScript 库提供类型信息
  • TypeScript 能够进行类型检查和代码提示
  • 在不修改源码的情况下添加类型支持
// 示例:一个简单的声明文件
// hello.d.ts
declare function sayHello(name: string): void;

// 声明文件只描述类型,不包含实现
// 编译后不会生成任何 JavaScript 代码

2,三种类型声明位置

TypeScript 中的类型声明有三种来源:
  • 内置类型声明TypeScript 自带的类型声明文件,如 lib.dom.d.ts
  • 外部定义类型声明:通过 @types/xxx 安装的第三方类型声明
  • 自定义类型声明:开发者自己编写的声明文件,如 global.d.ts

3,内置类型声明

(1)内置类型声明是 TypeScript 自带的,包含了 JavaScript 运行时的标准化 API 类型。常见的内置类型声明文件包括:
  • lib.es5.d.tsES5 标准库类型,如 ArrayObjectFunction
  • lib.dom.d.tsDOM API 类型,如 DocumentHTMLElementEvent
  • lib.es2015.d.tsES2015 新增类型,如 PromiseSymbol

(2)可以在 tsconfig.json 中通过 lib 字段配置需要的标准库:
注意:如果显式设置了 lib 字段,TypeScript 不会自动添加默认值,需要列出全部所需的库。
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"]  // 手动指定需要的标准库
  }
}

4,外部类型声明

(1)外部类型声明用于为第三方库添加类型支持。主要有两种方式:
  • 库自带声明:库内部包含 .d.ts 文件,如 axios
  • @types 包:通过 DefinitelyTyped 仓库维护的社区类型声明

(2)安装 @types 包样例:
提示:大多数流行的 JavaScript 库都有对应的 @types 包,可以在 npm 仓库搜索 @types/库名 来查找。
// 安装 React 的类型声明
npm install @types/react --save-dev

// 安装 lodash 的类型声明
npm install @types/lodash --save-dev

二、declare 声明全局变量、全局函数、全局类

1,什么是 declare

(1)declare 关键字用于告诉 TypeScript 编译器某个值已经存在,不需要实现它。declare 的作用如下:
  • 声明全局变量、函数、类
  • 声明模块和命名空间
  • 扩展第三方库的类型定义

(2)自定义声明文件命名可以随意,但必须是 .d.ts 文件,例如:shims-vue.d.tsglobal.d.tstypes.d.ts 等。

2,声明全局变量

(1)在 HTML 文件中定义全局变量:
<!-- public/index.html -->
<script>
  // 定义全局变量
  const appName = 'Vue.js 3 + TypeScript'
  const appVersion = '1.0.0'
</script>

(2)在 TypeScript 中直接使用会报错:
// main.ts
console.log(appName)     // 报错:Cannot find name 'appName'
console.log(appVersion)  // 报错:Cannot find name 'appVersion'

(3)使用 declare 声明全局变量:
提示:声明全局变量后,在项目的任何地方都可以直接使用,不再报错。
// src/types/global.d.ts

// 声明全局变量,告诉编译器该变量已声明
declare const appName: string
declare const appVersion: string

3,声明全局函数

(1)在 HTML 文件中定义全局函数:
<!-- public/index.html -->
<script>
  // 定义全局函数
  function getAppName() {
    return appName
  }
</script>

(2)声明全局函数:
// src/types/global.d.ts

// 声明全局函数
declare function getAppName(): string

// 或者使用函数类型声明
declare const getAppName: () => string

(3)使用全局函数:
// main.ts
console.log(getAppName())  // ok

4,声明全局类

(1)在 HTML 文件中定义全局类:
<!-- public/index.html -->
<script>
  // 定义全局类
  function Person(name, age) {
    this.name = name
    this.age = age
  }
</script>

(2)声明全局类:
// src/types/global.d.ts

// 声明全局类
declare class Person {
  name: string
  age: number
  constructor(name: string, age: number)
}

(3)使用全局类:
// main.ts
const p = new Person("hangge", 18)
console.log(p)

三、declare 声明文件与模块

1,声明导入的文件

(1)在前端开发中,经常需要导入图片、样式等文件。TypeScript 默认不知道如何处理这些导入,需要声明:
// src/types/global.d.ts

// 声明导入图片文件
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.png'
declare module '*.svg'
declare module '*.gif'

// 声明导入样式文件
declare module '*.css'
declare module '*.scss'
declare module '*.less'

(2)使用声明的文件导入:
提示:声明模块后,TypeScript 就知道如何处理这些文件的导入,不会再报错。
// main.ts
import logoImg from './img/logo.png'  // ok
import './styles/main.css'              // ok

2,声明第三方模块

(1)当使用没有类型声明的 JavaScript 库时,需要手动声明模块。例如使用 lodash
// 安装 lodash
npm install lodash --save

// 导入使用
import lodash from 'lodash'  // 报错:Could not find a declaration file for module 'lodash'

(2)有两种解决方案,一种方案是安装类型声明包:
npm install @types/lodash --save-dev

(3)另一种方案是手动编写声明文件,手动声明模块的语法如下。
注意:手动声明模块时,只声明实际使用到的方法即可,不需要声明所有方法。
// src/types/global.d.ts

// 声明 lodash 模块
declare module 'lodash' {
  // 导出模块中的函数
  export function join(args: any[]): any
  export function isEmpty(value: any): boolean
  // 可以继续导出 lodash 的其他方法
}

3,扩展模块类型

可以为已有的模块添加新的类型定义。例如扩展 axios
提示:模块扩展(Module Augmentation)允许在不修改原始库的情况下,为第三方库添加额外的类型定义。
// src/types/axios.d.ts

import 'axios'

declare module 'axios' {
  interface AxiosInstance {
    // 添加自定义方法
    customGet(url: string): Promise<any>
  }
}

四、声明命名空间

1,declare namespace 语法

(1)declare namespace 用于声明全局对象,该对象包含多个子属性和方法。

(2)典型应用场景是声明通过 CDN 引入的全局库,如 jQuery
<!-- public/index.html -->
<!-- 引入 jQuery -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>

(3)声明 jQuery $ 全局对象:
提示:在 declare namespace 内部,直接使用 functionconstclass 等声明成员,不需要再加 declare 关键字。
// src/types/global.d.ts

// 声明 $ 命名空间
declare namespace $ {
  function ajax(settings: any): void
  function get(url: string, callback: (res: any) => void): void
  function post(url: string, data: any, callback: (res: any) => void): void
}

(4)使用声明的全局对象:
// main.ts

// 全局使用 $ 函数不会提示报错
$.ajax({
  url: "https://api.example.com/get",
  success: (res: any) => {
    console.log(res)
  }
})

2,嵌套命名空间

(1)命名空间支持嵌套,用于组织复杂的类型结构:
// src/types/global.d.ts

declare namespace MyApp {
  // 嵌套命名空间
  namespace Utils {
    function formatDate(date: Date): string
    function parseJSON(str: string): any
  }
  
  namespace Config {
    const apiUrl: string
    const version: string
  }
}

// 使用
// MyApp.Utils.formatDate(new Date())
// console.log(MyApp.Config.apiUrl)

附:声明文件最佳实践

1,文件组织结构

(1)推荐的项目类型文件组织方式:
my-project/
├── src/
│   ├── index.ts
│   └── types/
│       ├── global.d.ts      // 全局类型声明
│       ├── vue.d.ts          // Vue 相关声明
│       └── modules.d.ts      // 模块声明

(2)推荐的 tsconfig.json 配置:
提示:即使不配置 typeRoots,只要 .d.ts 文件位于 include 范围内,TypeScript 都能正确识别。
// tsconfig.json
{
  "compilerOptions": {
    "typeRoots": [
      "./node_modules/@types",
      "./src/types"
    ]
  },
  "include": ["src"]
}

2,发布 npm 包时的配置

(1)如果要发布一个 TypeScript 库,需要在 tsconfig.json 中启用声明文件生成:
// tsconfig.json
{
  "compilerOptions": {
    "declaration": true,   // 自动生成 .d.ts 文件
    "outDir": "dist"
  }
}

(2)在 package.json 中指定类型文件位置:
注意types 字段(或 typings 字段)告诉 TypeScript 使用者该库的类型声明文件位置。
// package.json
{
  "name": "my-library",
  "main": "dist/index.js",
  "types": "dist/index.d.ts"  // 指定类型声明文件
}
评论

全部评论(0)

回到顶部