文章目录
-
- 一、什么是声明文件?
- 二、声明文件的两种来源
-
- [1. 内置声明文件(Bundled with package)](#1. 内置声明文件(Bundled with package))
- [2. DefinitelyTyped(@types/xxx)](#2. DefinitelyTyped(@types/xxx))
- 三、声明文件的基本语法
-
- [1. 声明全局变量/函数](#1. 声明全局变量/函数)
- [2. 声明模块(CommonJS / ES Module)](#2. 声明模块(CommonJS / ES Module))
- [3. 声明命名空间(常用于 UMD 库)](#3. 声明命名空间(常用于 UMD 库))
- [4. 声明类](#4. 声明类)
- [5. 扩展已有接口(Module Augmentation)](#5. 扩展已有接口(Module Augmentation))
- 四、如何编写自己的声明文件?
-
- [场景:你有一个纯 JS 库 `utils.js`,想在 TS 项目中使用并获得类型提示。](#场景:你有一个纯 JS 库
utils.js,想在 TS 项目中使用并获得类型提示。) -
- [步骤 1:创建 `utils.d.ts`](#步骤 1:创建
utils.d.ts) - [步骤 2:确保 TypeScript 能找到它](#步骤 2:确保 TypeScript 能找到它)
- [步骤 1:创建 `utils.d.ts`](#步骤 1:创建
- [场景:你有一个纯 JS 库 `utils.js`,想在 TS 项目中使用并获得类型提示。](#场景:你有一个纯 JS 库
- 五、高级技巧
-
- [1. 环境声明(Ambient Declarations)](#1. 环境声明(Ambient Declarations))
- [2. 三斜线指令(Triple-Slash Directives)](#2. 三斜线指令(Triple-Slash Directives))
- [3. 自动从 JS 生成 .d.ts(使用 JSDoc)](#3. 自动从 JS 生成 .d.ts(使用 JSDoc))
- [4. 发布带声明文件的 npm 包](#4. 发布带声明文件的 npm 包)
- 六、常见问题与最佳实践
- 七、参考资源
TypeScript 的声明文件(Declaration Files,通常以 .d.ts 为扩展名)是 TypeScript 类型系统的重要组成部分。它们不包含实际的 JavaScript 代码,只提供类型信息,用于描述已有 JavaScript 代码的结构,使得 TypeScript 能够在编译时进行类型检查、智能提示和重构支持。
一、什么是声明文件?
声明文件(.d.ts) 是 TypeScript 编译器用来理解 JavaScript 库或模块类型的"说明书"。当你使用一个没有原生 TypeScript 支持的 JavaScript 库(如 jQuery、Lodash、React 等)时,如果没有对应的类型信息,TypeScript 就无法知道该库导出了什么函数、类、接口等。
声明文件的作用就是告诉 TypeScript:
- 某个变量/函数/类长什么样
- 它有哪些参数、返回值、属性
- 模块导出的内容是什么
二、声明文件的两种来源
1. 内置声明文件(Bundled with package)
一些现代库(如 React、Vue、Axios)已经自带了 .d.ts 文件,发布在 npm 包中。你安装后 TypeScript 自动识别,无需额外操作。
例如:
bash
npm install axios
axios 包内包含 index.d.ts,TypeScript 会自动加载。
2. DefinitelyTyped(@types/xxx)
对于未自带类型定义的老库(如 jQuery、lodash),社区维护的 DefinitelyTyped 项目提供了高质量的类型定义。
安装方式:
bash
npm install --save-dev @types/jquery
TypeScript 会自动在 node_modules/@types 中查找匹配的声明文件。
注意:
@types包应作为 devDependency 安装,因为它们仅在开发/编译阶段使用。
三、声明文件的基本语法
1. 声明全局变量/函数
ts
// global.d.ts
declare const VERSION: string;
declare function greet(name: string): void;
2. 声明模块(CommonJS / ES Module)
ts
// mylib.d.ts
declare module 'mylib' {
export function doSomething(): number;
export interface Config {
timeout: number;
}
}
使用时:
ts
import { doSomething, Config } from 'mylib';
3. 声明命名空间(常用于 UMD 库)
ts
declare namespace moment {
function format(fmt: string): string;
interface Moment {
add(days: number): Moment;
}
}
4. 声明类
ts
declare class MyClass {
constructor(value: string);
getValue(): string;
}
5. 扩展已有接口(Module Augmentation)
ts
// 扩展 Express 的 Request 对象
declare global {
namespace Express {
interface Request {
user?: { id: string };
}
}
}
四、如何编写自己的声明文件?
场景:你有一个纯 JS 库 utils.js,想在 TS 项目中使用并获得类型提示。
步骤 1:创建 utils.d.ts
ts
// utils.d.ts
export function formatDate(date: Date): string;
export function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): T;
步骤 2:确保 TypeScript 能找到它
- 放在项目根目录或
types/目录下 - 在
tsconfig.json中配置:
json
{
"compilerOptions": {
"typeRoots": ["./node_modules/@types", "./types"]
}
}
或者直接引用:
ts
/// <reference path="./types/utils.d.ts" />
更推荐使用 模块声明 + import 方式,而非全局声明。
五、高级技巧
1. 环境声明(Ambient Declarations)
以 declare 开头的语句不会生成任何 JS 代码,仅用于类型检查。
2. 三斜线指令(Triple-Slash Directives)
ts
/// <reference types="node" />
/// <reference path="custom.d.ts" />
用于显式引入类型依赖(现在较少用,多被 import 替代)。
3. 自动从 JS 生成 .d.ts(使用 JSDoc)
如果你的 JS 项目使用 JSDoc 注解,可通过 tsc --allowJs --declaration --emitDeclarationOnly 生成 .d.ts。
示例:
js
// utils.js
/**
* @param {Date} date
* @returns {string}
*/
export function formatDate(date) {
return date.toISOString();
}
运行:
bash
tsc --allowJs --declaration --emitDeclarationOnly --outDir types utils.js
将生成 types/utils.d.ts。
4. 发布带声明文件的 npm 包
在 package.json 中指定:
json
{
"types": "dist/index.d.ts",
"main": "dist/index.js"
}
并确保构建流程生成 .d.ts(可用 tsc 或 rollup-plugin-dts 等工具)。
六、常见问题与最佳实践
| 问题 | 解决方案 |
|---|---|
| 找不到模块的类型 | 安装 @types/xxx,或自己写 .d.ts |
| 全局污染 | 避免在非全局模块中使用 declare var,优先使用模块化声明 |
| 类型冲突 | 使用 declare global 谨慎扩展全局对象 |
| 声明文件未生效 | 检查 tsconfig.json 的 include/typeRoots 配置 |
最佳实践:
- 优先使用官方或 DefinitelyTyped 提供的类型
- 自定义声明文件放在
types/目录,结构清晰 - 避免过度使用
any,尽量精确描述类型 - 利用
declare module为第三方 JS 库"打补丁"