如何为JavaScript NPM库生成包含作用域包名的单模块.d.ts声明文件
我完全懂你的困扰——你想让TypeScript把带JSDoc注释的JS库,打包成一个以你的作用域包名(@myscope/mylib)为模块名的单文件.d.ts声明,但现在生成的却是分散的子模块声明,导致VS Code导入路径全错了。
咱们先捋清楚问题出在哪:你当前的tsconfig里用了outFile选项,但对于ES模块规范的JS文件来说,TypeScript会默认把每个文件当成独立模块处理,所以生成的声明会用declare module包裹每个子模块,而非把所有导出合并到你的入口模块中。另外,VS Code导入路径出错也和你的package.json包名配置脱不了干系。
下面是一步到位的解决方案:
第一步:先把package.json配置对
这是VS Code能正确识别你包名的基础,一定要先设置好:
{ "name": "@myscope/mylib", // 你的作用域包名 "types": "index.d.ts", // 指定包的类型入口文件 "main": "index.js" // 指定包的代码入口文件 }
第二步:调整TypeScript配置,生成分散的声明文件
修改你的tsconfig.json,移除outFile选项(它是导致子模块声明的元凶),改用declarationDir指定声明输出目录,同时确保包含所有JS文件:
{ "include": ["index.js", "foo.js", "bar.js"], "compilerOptions": { "allowJs": true, "declaration": true, "emitDeclarationOnly": true, "declarationMap": true, "rootDir": "./", // 源码根目录 "module": "ESNext", // 匹配你的ES模块代码 "moduleResolution": "NodeNext" } }
运行tsc后,会生成index.d.ts、foo.d.ts、bar.d.ts三个文件,其中index.d.ts的内容是:
export * from "./foo.js"; export * from "./bar.js";
第三步:合并为带作用域名的单模块声明
想要直接生成declare module "@myscope/mylib"格式的声明,最省心的方式是用dts-bundle-generator这个专门做声明合并的工具:
- 先安装依赖:
npm install -D dts-bundle-generator
- 运行生成命令,指定你的作用域包名和输出文件:
dts-bundle-generator --name "@myscope/mylib" --output index.d.ts index.js
执行完这条命令,你就能得到完全符合预期的index.d.ts:
declare module "@myscope/mylib" { /** This is the foo function */ export function foo(): void; /** This is the bar function */ export function bar(): void; }
替代方案:手动合并(适合小型项目)
如果不想加第三方依赖,也可以手动创建顶层声明文件:
// index.d.ts declare module "@myscope/mylib" { export * from "./index"; }
然后把tsc生成的原index.d.ts改名为lib.d.ts(避免文件名冲突),这样VS Code也能正确识别整个包的类型,导入时自动提示@myscope/mylib路径。
最后验证一下:完成上面的步骤后,在项目里导入时,VS Code会自动弹出import { foo, bar } from "@myscope/mylib"的提示,再也不会出现子模块的错误路径了。
备注:内容来源于stack exchange,提问作者Brad Robinson

