NRWL NX库使用TypeScript ambient声明文件避免导入时编译报错
现有配置
我在新的NX工作空间中有如下基础配置:
- /apps/my-app(node类型)
- /libs/some-lib(node类型)
二者均通过nx cli命令创建,示例命令:nx g @nrwl/node:lib some-lib --simpleModuleName=true
我需要在库中使用ambient声明文件(.d.ts),于是在/libs/some-lib/src/types/index.d.ts路径下添加了声明文件,内容如下:
declare type MyCustomType = any;
据我了解该文件会基于/libs/some-lib/tsconfig.lib.json处理,我还在/libs/some-lib/tsconfig.json中直接添加了该文件的引用:
{ "extends": "../../../tsconfig.base.json", "files": [ "src/types/index.d.ts" ], "include": [ "src/types/**/*.d.ts" ], "references": [ { "path": "./tsconfig.lib.json" }, { "path": "./tsconfig.spec.json" } ] }
在库内部代码中使用该类型时IDE识别正常,比如在/libs/some-lib/src/lib/file.ts中如下写法无报错:
export const x: MyCustomType = 1;
但当我在my-app中导入这个变量并执行nx serve my-app启动应用时:
import { x } from '@my-workspace/some-lib';
编译器抛出如下错误:
ERROR in libs/some-lib/src/lib/file.ts TS2304: Cannot find name "MyCustomType".
问题诉求
有没有方法可以在库内部使用ambient声明文件,同时避免导入该库的应用运行时报错?
我已知可以在根目录创建公共类型文件types/myCustomType.d.ts,再在应用和库的tsconfig的files属性中引入该文件,但我希望类型和业务代码放在一起,不想采用该方案。
另一个可用但非常不优雅的方案是在my-app的tsconfig文件中添加库的额外引用:
{ "path": "../../libs/some-lib/tsconfig.json" }
修改后/apps/my-app/tsconfig.json内容如下:
{ "extends": "../../tsconfig.base.json", "files": [], "include": [], "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.spec.json" }, { "path": "../../libs/node/schedulers/tsconfig.json" } ] }
或者创建tsconfig.json聚合文件/libs/tsconfig.json,在其中引用所有相关库,my-app的tsconfig只需要引用这一个文件即可,但该方案也不符合我的预期。
解决方案
方案1(推荐,无全局污染)
不使用全局ambient声明,改为导出式类型模块,在使用处显式导入:
- 修改
/libs/some-lib/src/types/index.d.ts内容:
export type MyCustomType = any;
- 在用到该类型的库文件头部导入:
import type { MyCustomType } from '../types'; export const x: MyCustomType = 1;
该方案无需修改任何tsconfig配置,不会污染全局类型命名空间,类型完全收敛在库内部,符合类型与业务代码共存的要求。
方案2(保留全局ambient声明)
将类型文件引用配置从库根的tsconfig.json移动到库的编译配置/libs/some-lib/tsconfig.lib.json中:
{ "extends": "./tsconfig.json", "files": [ "src/types/index.d.ts" ], "include": [ "src/**/*.ts", "src/types/**/*.d.ts" ], // 保留原有compilerOptions、exclude等配置不变 }
原写法IDE识别正常但编译报错的原因是:库根的tsconfig.json仅用于IDE全局索引,实际编译时NX会使用tsconfig.lib.json的配置,你之前的类型引用没有被编译配置加载,导致编译时找不到类型定义。修改后无需改动应用侧任何配置,编译即可正常通过。
内容的提问来源于stack exchange,提问作者Pawel Miatkowski

