TypeScript如何在.d.ts文件中正确引用DOM类型定义
问题描述
开发需同时面向浏览器环境、Web Worker环境编译的JavaScript应用时,在.d.ts类型声明文件中引用TypeScript内置DOM定义的HTMLButtonElement类型,编译器抛出错误:Cannot find name 'HTMLButtonElement'。
示例foo.d.ts文件代码如下:
interface SomeInterface { getButtonInfo: (element: HTMLButtonElement) => Info; }
根目录tsconfig.json的compilerOptions.lib配置项已引入dom类库,HTMLButtonElement这类DOM类型在应用其他业务代码中都可以作为环境全局类型正常识别。
相关配置文件如下:
- 根目录
tsconfig.json
{ "compileOnSave": false, "compilerOptions": { "baseUrl": "./", "outDir": "./dist/out-tsc", "forceConsistentCasingInFileNames": true, "strictPropertyInitialization": false, "strict": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": false, "noUnusedParameters": false, "noUncheckedIndexedAccess": false, "resolveJsonModule": true, "sourceMap": true, "declaration": false, "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "moduleResolution": "node", "importHelpers": true, "target": "es2020", "module": "es2020", "lib": [ "es2019", "dom" ] }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, "strictInputAccessModifiers": true, "strictTemplates": true } }
- 浏览器端编译配置
tsconfig.app.json
{ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/app", "types": [ "node" ] }, "files": [ "src/main.ts", "src/polyfills.ts" ], "include": [ "src/**/*.d.ts" ], "exclude": [ "src/**/*.worker.ts" ] }
- Web Worker端编译配置
tsconfig.worker.json
{ "extends": "../../tsconfig.json", "compilerOptions": { "allowJs": true, "outDir": "../../out-tsc/worker", "lib": [ "es2018", "webworker" ], "types": [ "node" ] }, "include": [ "src/**/*.d.ts", "src/**/*.worker.ts" ] }
错误原因
项目配置了两个互相独立的TypeScript编译上下文:
- 浏览器端上下文继承根配置,
lib包含dom类型定义,可以正常识别全局DOM类型 - Web Worker端上下文重写了
lib配置,仅引入es2018和webworker类库,没有内置DOM类型定义
两个编译上下文的include规则都覆盖了src/**/*.d.ts路径,通用.d.ts文件会同时被两个上下文加载处理。Worker上下文扫描到依赖HTMLButtonElement的类型声明时,自身类型库中不存在该类型,就会抛出找不到名称的错误。
普通业务代码通过files、exclude规则做了环境隔离,浏览器端代码不会被Worker上下文编译,Worker代码也不会被浏览器端上下文编译,因此不会出现同类报错。
解决方案
根据类型的实际使用场景选择对应方案即可:
- 若该类型仅在浏览器端业务逻辑中使用:将依赖DOM类型的声明从通用
.d.ts中拆分,移动到仅被浏览器端编译上下文扫描、不会被Worker上下文匹配到的路径(例如新建src/types/browser/目录存放这类声明),同时在tsconfig.worker.json的exclude规则中添加该目录路径,避免Worker上下文加载浏览器专属类型。 - 若该类型需要同时被浏览器、Worker两端的逻辑引用:在对应
.d.ts文件顶部添加三斜线指令,显式为当前文件引入DOM类型库,修改后的代码如下:
/// <reference lib="dom" /> interface SomeInterface { getButtonInfo: (element: HTMLButtonElement) => Info; }
该指令仅会为当前声明文件补充DOM类型依赖,不会将DOM类型注入到Web Worker的全局类型空间,不会导致Worker代码中误访问DOM API的问题。
- 不推荐的方案:直接在
tsconfig.worker.json的lib数组中添加dom。这种方式会让Worker编译上下文全局注入DOM类型,和Web Worker的实际运行环境不符,容易写出编译通过但运行时报错的代码。
内容的提问来源于stack exchange,提问作者Joseph Zabinski
相关产品推荐
相关产品推荐

