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

关于TypeScript创建Chrome扩展content scripts专属d.ts文件的技术问询

Chrome扩展Content Scripts适配TypeScript全局类型问题

作为TypeScript初/中级用户,我正在为Chrome扩展的Content Scripts场景创建global.d.ts文件,因为Content Scripts只能访问有限的扩展API子集。以下是我的初步尝试代码:

export {}

declare global {
    interface Window {
        chrome: Chrome
    }
    const chrome: Chrome // 后续会针对此行提问
}

interface Chrome {
    runtime: import('../node_modules/@types/chrome/index.d.ts').runtime
    // 我知道这语法不对,Content Scripts的chrome.runtime只是完整API的子集,这里仅作示意
    // 还需要添加storage、dom、i18n等命名空间
}

我之前仅少量接触d.ts文件(已为扩展服务工作者上下文创建了单独的global.d.ts),希望解答以下问题:

  1. 是否已存在Content Scripts专属的类型库?我在DefinitelyTyped中未找到;
  2. d.ts文件能否导入另一个d.ts文件的部分类型?我不想重复编写已有类型;
  3. 示例:如何声明全局的[window.]chrome.runtime.sendMessage并重用@types/chrome中的chrome.runtime.sendMessage类型?
  4. 如何排除@types/chrome中其余的全局/命名空间?@types/chrome/index.d.ts中包含interface Window { chrome: typeof chrome; };
  5. 附带问题:Content Scripts运行在DOM上下文(即globalThis为Window),但我发现仅通过declare global { interface Window { foo: string } }时,VSCode无法解析全局foo,必须通过window.foo访问或额外声明const foo: string,这是为什么?

问题解答

1. 是否存在Content Scripts专属的类型库?

目前DefinitelyTyped上没有专门为Content Scripts拆分的独立类型库,@types/chrome提供的是Chrome扩展全API的类型定义,覆盖了背景页、Popup、Content Scripts等所有场景的API。如果需要适配Content Scripts的受限API,只能基于@types/chrome自行裁剪类型。

2. d.ts文件能否导入另一个d.ts文件的部分类型?

可以,TypeScript支持类型导入语法,无需导入整个模块就能复用目标d.ts中的特定类型,常用两种写法:

  • 直接在类型定义中使用import(...)类型查询
  • 顶部用import type导入具体类型

示例:

// 方式1:类型查询
interface ChromeRuntime {
  sendMessage: import('chrome').runtime.sendMessage
}

// 方式2:显式类型导入
import type { runtime } from 'chrome';
type ChromeRuntimePick = Pick<typeof runtime, 'sendMessage' | 'getURL'>;

3. 如何声明全局的[window.]chrome.runtime.sendMessage并重用已有类型?

通过类型导入提取@types/chrome中的sendMessage类型,定义Content Scripts可用的Chrome子集接口,最后声明全局变量和Window接口属性即可:

export {}

// 从@types/chrome导入所需的类型片段
import type { runtime, storage } from 'chrome';

// 定义仅包含Content Scripts可用API的Chrome接口
interface Chrome {
  runtime: Pick<typeof runtime, 'sendMessage' | 'getURL' | 'onMessage'>
  storage: Pick<typeof storage, 'local'>
  // 按需添加i18n、dom等其他可用API
}

declare global {
  // 声明window上的chrome属性
  interface Window {
    chrome: Chrome
  }
  // 声明全局chrome变量,支持直接访问chrome.runtime.sendMessage
  const chrome: Chrome
}

这样既重用了@types/chrome的原有类型,又只保留了Content Scripts能访问的API子集。

4. 如何排除@types/chrome中其余的全局/命名空间?

@types/chrome会默认在全局注入完整的chrome类型和Window接口扩展,要覆盖这个行为可按以下步骤操作:

  1. 在tsconfig.json中,将types字段设为[],避免自动导入所有全局类型:
    {
      "compilerOptions": {
        "types": []
      }
    }
    
  2. 在自己的global.d.ts中,通过import type手动导入需要的类型片段,再重新声明全局的chrome变量和Window接口,自己的类型定义会覆盖@types/chrome的全局注入。
  3. 若仍有局部冲突,可临时用// @ts-expect-error忽略,但不推荐长期使用。

5. 为什么仅声明Window中的foo无法直接访问全局foo?

TypeScript的类型系统不会自动将Window接口的自定义属性提升为全局变量,只有浏览器原生的全局属性(比如document、console)会被默认识别为全局变量。

要实现直接访问全局foo,必须在declare global块中额外声明全局变量:

export {}

declare global {
  interface Window {
    foo: string
  }
  // 声明全局变量foo,让TypeScript识别为全局可访问
  const foo: string
}

否则只能通过window.foo访问自定义的Window属性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:55:54