Skip to main content
Extension.js compiles TypeScript with SWC, which strips types and never checks them. Type checking is a separate step that you run with tsc. This page covers the packages that step needs to resolve chrome.* and browser.*.

What Extension.js generates

When a project uses TypeScript, extension dev and extension build write an extension-env.d.ts file beside package.json. It is regenerated on every run, so do not edit it. The file pulls in the ambient types that the extension package publishes:
extension-env.d.ts
Those references give you: The EXTENSION_* environment keys are typed here too. That is why process.env.EXTENSION_MODE resolves without extra setup.

Install @types/chrome for the chrome namespace

extension/types declares the browser global itself, but it reaches the chrome namespace through a reference:
That reference resolves only when @types/chrome is installed in your project. Extension.js does not install it, and the templates do not declare it. A scaffolded TypeScript project that calls chrome.storage therefore fails tsc:
Install the package to clear it:
Run the check again and the errors are gone:
Nothing else changes. The build already succeeded before the install, because SWC never reads the types.

When you write browser.* instead

The browser global is typed by extension/types, which maps it onto webextension-polyfill. For the full namespace shape, add the matching types package:
Read Cross-browser compatibility for the runtime side of the same choice.

Keep extension-env.d.ts in the include list

The generated file only helps when TypeScript reads it. The scaffolded tsconfig.json names it:
tsconfig.json
When Extension.js writes a tsconfig.json for a project that has none, that file carries no include array. TypeScript then reads every file under the project folder, so it finds extension-env.d.ts anyway. An include array of your own that omits the file breaks asset imports and the browser global.

Symptoms and fixes

Best practices

  • Treat extension-env.d.ts as build output. Commit it if you like, but never edit it.
  • Add @types/chrome to any TypeScript project that calls chrome.*, including one that you scaffolded from a template.
  • Run tsc --noEmit in continuous integration. The Extension.js build does not fail on type errors.

Next steps