主题
声明文件
声明文件通常指 .d.ts 文件,用来描述值的类型信息,而不提供实际运行时代码。
可以把它理解为“只告诉 TypeScript 这段 API 长什么样,不负责真正实现”。
作用
声明文件主要解决以下问题:
- 让 TypeScript 理解现有 JavaScript 库的类型
- 为没有类型信息的全局变量、函数或模块补充定义
- 给自己编写的库提供类型提示和类型检查能力
- 让编辑器获得更准确的补全、跳转和报错信息
什么是 .d.ts
.ts 文件既可以写类型,也可以写运行时代码。
.d.ts 文件只用于声明类型,不会被编译成实际 JavaScript 逻辑。
ts
// math.d.ts
declare function add(x: number, y: number): number这里的 add 只是“声明存在”,并没有真正实现。
什么时候需要声明文件
- 使用没有自带类型的 JavaScript 库
- 需要给项目里的全局变量补类型
- 维护 TS/JS 混合项目
- 编写要给其他人使用的库
如果一个包已经自带类型,或者已经安装了对应的 @types/*,通常就不需要自己再写一份声明文件。
常见写法
全局声明
适合给全局变量、全局函数或全局接口补类型。
ts
// globals.d.ts
declare const APP_VERSION: string
declare function track(event: string): void
interface Window {
__APP_NAME__: string
}这类写法常见于浏览器环境注入变量、构建时常量或脚本标签挂到全局对象上的能力。
模块声明
适合给某个模块名补充类型定义。
ts
// types/math.d.ts
declare module 'math' {
export function add(x: number, y: number): number
export function subtract(x: number, y: number): number
}当代码里执行:
ts
import { add } from 'math'TypeScript 就可以从这份声明中知道 add 的参数和返回值类型。
为现有库补声明
如果项目中接入了一个没有类型的 JavaScript 文件,也可以单独为它补一份 .d.ts。
ts
// my-library.d.ts
declare namespace MyLibrary {
function doSomething(input: string): void
function getValue(): number
}这类写法更常见于历史全局库或非模块化脚本。
常见关键字
声明文件里经常会看到以下关键字:
declare:声明某个值或类型存在declare module:声明一个模块declare namespace:声明一个命名空间declare global:扩展全局作用域
例如扩展全局类型时,常见写法如下:
ts
export {}
declare global {
interface Window {
__INITIAL_DATA__: {
userId: string
}
}
}如何接入项目
方式一:让 .d.ts 文件参与编译
只要声明文件位于 tsconfig.json 的 include 范围内,TypeScript 就会自动读取。
json
{
"include": ["src", "types"]
}方式二:配置 typeRoots
如果希望显式指定类型根目录,可以使用 compilerOptions.typeRoots。
json
{
"compilerOptions": {
"typeRoots": ["./types", "./node_modules/@types"]
}
}适合把项目自定义声明和第三方类型来源分开管理。
方式三:配置 types
如果只想启用指定的类型包,可以使用 compilerOptions.types。
json
{
"compilerOptions": {
"types": ["node", "vite/client"]
}
}这会限制自动注入的全局类型范围。
和 @types/* 的关系
很多第三方包的类型定义由社区维护在 DefinitelyTyped 仓库中,安装后通常以 @types/* 的形式提供。
例如:
bash
npm i -D @types/jquery安装后,TypeScript 就能识别 jQuery 的类型信息。
优先级上通常是:
- 包自带类型:直接使用
- 没有自带类型,但有
@types/*:安装对应类型包 - 两者都没有:再考虑自己写声明文件
和三斜线指令的关系
声明文件负责“定义类型内容”。
三斜线指令负责“告诉编译器去额外加载哪些类型信息”。
简单理解:
.d.ts:定义类型本身/// <reference ... />:补充编译器的读取入口
现代项目里,通常优先用:
tsconfig.jsonincludetypes- 正常的模块导入
只有在文件级补充或历史代码场景下,才更常用三斜线指令。
注意事项
- 声明文件不应该写真实业务实现
- 全局声明要谨慎,避免污染命名空间
- 能写成模块类型时,优先写成模块,不要滥用全局声明
- 自定义声明与第三方声明最好按目录分开管理
