如何将TypeScript类型声明导出为可复用的NPM包?
针对你要把共享TS类型声明打包发布到NPM的场景,逐个解答你的问题:
问题1:应导出*.d.ts还是转为*.ts文件供其他项目使用?
直接用*.d.ts文件即可。d.ts是TypeScript专门用于存放类型定义的文件,其他TS项目可以直接识别,无需转成.ts——转成.ts反而会增加用户的编译成本,完全没必要。
问题2:是否需要创建index.d.ts或index.ts文件来导出declarations文件夹下的所有文件?
必须创建。这是NPM包的入口规范,能让用户通过import { LatLng } from 'your-package-name'直接导入类型,不用写冗长的内部路径。推荐在/declarations目录下创建index.d.ts,统一导出所有子文件的类型:
// declarations/index.d.ts export { LatLng, MapMarker } from './maps.d.ts'; export { OtherType } from './other-file.d.ts'; // 其他类型文件的导出同理
问题3:是否需要先通过npm run build或rollup等命令编译为纯JavaScript文件,还是可直接导入源码到其他项目?
不需要编译成JS文件。你的包只有类型声明,没有可执行的JS代码,直接发布d.ts文件即可,TypeScript会自动处理类型导入。
问题4:尝试导出maps.d.ts时TypeScript提示“不是模块”,是否需要将文件包裹在declare module 'mapsModule' { ... }中?
不需要。declare module 'xxx'这种写法是给非TS项目补充全局类型用的,而你要做的是ES模块导出,用模块级别的导出更规范,也符合NPM包的使用习惯。
问题5:若不需要,直接使用export interface MapMarker { ... }是否可行?
完全可行。这是TS模块导出的标准写法,只要每个d.ts文件里的类型都用export标记,就能被其他文件导入并汇总到入口文件中。示例:
// declarations/maps.d.ts export interface LatLng { lat: number; lng: number; } export interface MapMarker { position: LatLng; title: string; }
问题6:是否需要在package.json中添加"types"字段指定主声明文件?
必须添加。这是告诉TypeScript你的包的主类型入口位置,同时也是NPM包的标准配置。另外建议加上files字段,明确指定要发布的文件,避免上传无关内容:
{ "name": "your-types-package-name", "version": "1.0.0", "types": "./declarations/index.d.ts", // 主类型入口 "files": [ "declarations/**/*.d.ts" // 明确要发布的所有类型文件 ], "type": "module" // 如果用ES模块规范,建议加上这个 }
问题7:是否需要在根目录添加index.ts或index.d.ts文件,从/declarations/index.d.ts导入内容?
可选。如果已经在package.json的types字段指定了./declarations/index.d.ts,用户可以直接导入,根目录不需要额外文件。但如果想隐藏内部目录结构,让用户导入路径更简洁,可以在根目录创建index.d.ts,内容如下:
// 根目录index.d.ts export * from './declarations/index.d.ts';
这样用户只需写import { MapMarker } from 'your-package-name',不用关心内部的declarations目录。
学习资料建议
- 重点看TypeScript官方文档的「Declaration Files」章节,尤其是「Publishing Declaration Files」部分,里面详细讲了类型包的发布规范
- 参考知名纯类型NPM包的源码(比如
@types/node),学习它们的目录结构和package.json配置
内容的提问来源于stack exchange,提问作者mlvrkhn

