TypeScript 中的 .d.ts 声明文件
说明 .d.ts 为什么存在、它在包发布和 monorepo 类型传递里承担什么角色,以及它和运行时代码、全局声明、声明生成选项的边界。
#tech / dev
#resource / typescript
#type / concept
#status / growing
[!info] related notes
TypeScript 中的 .d.ts 声明文件
一句话定义
.d.ts 是 TypeScript 用来描述一个模块或全局环境“对外暴露了哪些类型和签名”的声明文件。
核心机制 / 工作原理
它保留类型面,不保留实现体
假设源码里有:
export class AiProviderConfig {
uuid: string;
name: string;
validate(): Result<AiProviderConfig> {
// implementation
}
}
生成出的 .d.ts 更像:
export declare class AiProviderConfig {
uuid: string;
name: string;
validate(): Result<AiProviderConfig>;
}
也就是说:
- 类型信息会保留
- 导出面会保留
- 运行时实现会被移除
TypeScript、IDE 和 tsserver 读取的是这层“类型接口面”,而不是运行时代码本身。
它把运行时入口和类型入口分开
一个被发布的包,通常同时需要:
.js让 Node / bundler 在运行时执行.d.ts让 TypeScript 在编译期理解类型
因此 package.json 经常会同时出现:
{
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
}
}
运行时代码和类型契约是两条平行链路,只是它们一起对外暴露。
最小例子 / 最小场景
场景 1:消费一个库包
下游包写:
import { AiProviderConfig } from '@dailyuse/ai/infrastructure-server';
TypeScript 需要知道 AiProviderConfig 长什么样,就会去读该子路径对应的:
./dist/infrastructure-server/index.d.ts
而不是强制去读 @dailyuse/ai 的源码实现。
场景 2:没有声明文件
如果包只有 .js,却没有可用的 .d.ts,常见后果是:
- 报找不到声明文件
- 或整个模块退化成
any
这样下游的自动补全、类型检查和声明生成都会变差。
常见用途
- npm library 对外发布类型
- monorepo 中让下游包消费上游类型而不直接拉源码
- 给纯 JavaScript 包补类型信息
- 在
.d.ts中做全局声明或模块扩展
边界与易混淆点
.d.ts 不是运行时代码
它不会被执行,也不能替代真实的 .js 实现。
更准确地说:
.js决定代码怎么跑.d.ts决定 TypeScript 怎么理解这段代码
.d.ts 不只来自自动生成
它有两种常见来源:
- 从
.ts源码自动 emit - 手写声明文件
手写的常见场景包括:
- 给旧的 JS 包补类型
- 给全局变量补类型
- 给第三方模块做扩展
没有 .d.ts 不等于包不能运行
很多包即使没有声明文件,运行时仍然能正常工作。
但从 TypeScript 的角度看,它就更像一个“无类型黑盒”。这对库消费、重构和跨包声明传递都不利。
在 monorepo 里,它常被当成包边界
对于多层库依赖,更稳的构建链通常是:
- 上游包先产出
.d.ts - 下游包消费上游
.d.ts - 下游再生成自己的
.d.ts
这样每一层都只消费上游的声明面,而不是把整个源码类型图继续往下拉。
它和 declare、declaration、emitDeclarationOnly 不是一回事
.d.ts是产物或文件形态declare是声明语法declaration是生成.d.ts的开关emitDeclarationOnly是“只生成声明,不生成 JS”的开关
把它们分开理解,配置和排障会清楚很多。
参考信息
- TypeScript Handbook: Declaration Files — https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html
- TSConfig
declaration— https://www.typescriptlang.org/tsconfig/#declaration - TSConfig
emitDeclarationOnly— https://www.typescriptlang.org/tsconfig/emitDeclarationOnly.html