You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从类型声明文件导入并重命名Firefox WebExt的browser类型?

问题:能否从类型声明文件导入类型并重命名?

我尝试用以下代码导入Firefox扩展的类型并重命名:

import { browser as webextBrowser } from '@types/firefox-webext-browser'

但触发了两个TypeScript错误:

File '.../node_modules/@types/firefox-webext-browser/index.d.ts' is not a module. ts(2306)
Cannot import type declaration files. Consider importing 'firefox-webext-browser' instead of '@types/firefox-webext-browser'. ts(6137)

背景

我在用WebdriverIO测试Firefox浏览器扩展,扩展需要访问书签等功能,但WebdriverIO没有提供修改书签的API。于是我利用扩展的书签权限,通过WebdriverIO的browser.execute在扩展上下文执行代码来设置测试用书签(知道这种方法比较取巧,欢迎提供更好的方案)。

当前代码如下:

browser.execute(async (url) => {
  // @ts-expect-error: does not know about web-extension types
  await browser.bookmarks.create({ url: url })
}, url)

这段代码运行正常,但编译阶段有问题:外层的browser是WebdriverIO类型,内层的browser是WebExt类型。我只能用@ts-expect-error抑制错误,但typescript-eslint会告警,而且误用WebExt类型也得不到编译提示。

我希望能把WebExt类型以别名(比如webextBrowser)导入,避免类型冲突,同时给browser.execute传入的函数提供类型提示。

补充说明

  • @types/firefox-webext-browser只有类型声明文件,没有对应的firefox-webext-browser模块,因为实现是浏览器提供的。
  • 在tsconfig.json的types: [ ... ]里加@types/firefox-webext-browser没用,反而会导致不同browser类型冲突。把WebdriverIO的browser别名导入虽然可行,但WebdriverIO的browser在测试代码里大量使用,WebExt的browser只在browser.execute里用,这么做太麻烦。
  • 试过用三斜线指令在单独文件里导出:
    /// <reference types="firefox-webext-browser" />
    export const webextBrowser = browser
    
    VS Code里用webextBrowser时能识别类型,但typescript-eslint会报no-unsafe-*错误,WebdriverIO配置文件wdio.conf.ts里的browser会错误指向WebExt类型,导致TypeScript错误,而且运行时会出现“ReferenceError: webextBrowser is not defined”的报错。

解决方案

方法1:类型断言+自定义类型模块

创建一个类型声明文件(比如webext-types.d.ts),封装WebExt的类型别名:

declare module 'webext-browser-types' {
  import type { browser } from '@types/firefox-webext-browser';
  export { browser as webextBrowser };
}

在需要的地方导入类型并做断言:

import type { webextBrowser } from './webext-browser-types';

browser.execute(async (url) => {
  // 断言当前上下文的browser为WebExt类型
  const webextBrowser = browser as typeof import('./webext-browser-types').webextBrowser;
  await webextBrowser.bookmarks.create({ url });
}, url);

这种方式既隔离了类型,又不会引入运行时依赖。

方法2:直接内联类型断言(最简方案)

不需要额外文件,直接在回调里给browser做类型断言:

browser.execute(async (url) => {
  const webextBrowser = browser as import('@types/firefox-webext-browser').browser;
  await webextBrowser.bookmarks.create({ url });
}, url);

适合只在少数场景使用的情况,简洁高效。

方法3:局部类型隔离(不推荐)

如果不想重复写断言,可以在单个测试文件顶部用三斜线指令,仅让当前文件识别WebExt类型,同时保存WebdriverIO的类型:

/// <reference types="@types/firefox-webext-browser" />

// 保存WebdriverIO的browser类型
type WdioBrowser = typeof browser;

// execute回调内直接用WebExt的browser类型
browser.execute(async (url: string) => {
  await browser.bookmarks.create({ url });
}, url);

// 其他场景用断言转回WebdriverIO类型
const wdioBrowser = browser as WdioBrowser;
wdioBrowser.url('https://example.com');

但这种方式容易混淆类型,不推荐在大量代码中使用。

替代方案:使用官方WebExtension测试API

Firefox提供了专门的WebExtension测试API,可以直接在测试中调用扩展的书签等功能,不需要通过browser.execute中转。这种方式类型支持更完善,流程也更规范,建议优先尝试。


内容的提问来源于stack exchange,提问作者Marcono1234

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:44:51