为什么声明文件很重要
当您发布用 TypeScript 编写的 npm 包时,使用者需要类型信息来获取 IntelliSense 和编译时检查。如果没有 .d.ts 文件,您的库实际上会被键入为 any,这从一开始就违背了使用 TypeScript 的目的。
声明文件描述了导出的形状,而无需运送实施源。它们可以在消费者项目中实现树摇动、文档悬停提示和严格的类型检查。
生成 .d.ts 文件
当 declaration 设置为 tsconfig.json 中的 true 时,TypeScript 编译器会生成声明文件。
{
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
| 选项 | 目的 |
|---|---|
| 占位符_0 | 与 .js 输出一起发出 .d.ts 文件 |
| 占位符_0 | 生成声明的源映射(在编辑器中转到定义) |
| 占位符_0 | 仅发出声明,不发出 JS(当另一个工具处理捆绑时使用) |
| 占位符_0 | JS 和 .d.ts 文件的输出目录 |
运行构建:
npx tsc
输出结构反映了您的 src/ 布局。文件 src/index.ts 生成 dist/index.js 和 dist/index.d.ts。
Package.json 类型字段
types 字段(或其别名 typings)指向条目声明文件。
{
"name": "my-library",
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
}
对于双 ESM/CJS 包,exports 字段提供条件解析:
{
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"./subpath": {
"import": {
"types": "./dist/subpath.d.mts",
"default": "./dist/subpath.mjs"
},
"require": {
"types": "./dist/subpath.d.ts",
"default": "./dist/subpath.js"
}
}
}
}
这告诉 TypeScript 为 import 语句加载 index.d.mts ,为 require() 调用加载 index.d.ts 。
三斜线指令
在手写的环境声明中,使用三斜杠指令来引用其他类型。
/// <reference types="node" />
/// <reference path="./custom-types.d.ts" />
export function readConfig(path: string): Buffer;
这些仅在 .d.ts 文件中有效,在实现 .ts 文件中无效。对于生成的声明,请改为依赖普通的 import 语句。
在您的包裹中包含声明
package.json 中的 files 字段控制发布到 npm 的内容:
{
"files": [
"dist",
"!dist/**/*.test.d.ts",
"README.md",
"LICENSE"
]
}
始终排除测试声明文件和源 .ts 文件,除非您打算发布它们。
测试你的声明
在发布之前,验证消费者是否可以正确解析您的类型。
# Create a test project
mkdir test-consumer && cd test-consumer
npm init -y
npm link ../my-library
import { MyType } from "my-library";
const x: MyType = { /* ... */ };
在测试项目中运行 npx tsc --noEmit 。如果编译没有错误,则您的声明是正确的。
常见陷阱
| 问题 | 解决方案 |
|---|---|
.js 文件缺少 .d.ts | 在 tsconfig |
消费者看到 any 而不是正确的类型 | 验证 types 字段指向正确的条目 |
| 双 ESM/CJS 类型无法解决 | 将 exports 与单独的 types 条件一起使用 |
| 声明源图已损坏 | 添加 declarationMap: true |
| 公共 API 中的私有类型泄露 | 在内部类型前面加上 _ 前缀或使用 @internal JSDoc 标签 |
概括
正确生成和发布声明文件可确保您的 TypeScript 库提供一流的开发人员体验。在 tsconfig 中配置 declaration: true,在 package.json 中设置 types 字段,对双模块包使用 exports,并在发布之前始终针对消费者项目测试您的声明。

