Thunderbird WebExtension Typings

Typings for Thunderbird's WebExtension APIs: autocomplete, parameter hints and earlier error detection, for add-ons written in JavaScript or TypeScript.

Download

The links open the file as text, use "Save link as" to download it.

mv3.d.ts Manifest V3
mv2.d.ts Manifest V2

Use it in VS Code

Save the file in your add-on, for example as types/mv3.d.ts (mv2.d.ts for a Manifest V2 add-on), and add a jsconfig.json next to your manifest.json:

{
  "compilerOptions": {
    "target": "es2022",
    "module": "esnext",
    "moduleResolution": "bundler",
    "checkJs": false,
    "lib": ["es2022", "dom"]
  },
  "include": ["types/mv3.d.ts", "**/*.js"]
}

Then close and re-open VS Code. Typing messenger.messages. now lists the available APIs, and hovering a call shows its parameters and return type.

Use it from npm

npm install @thunderbirdops/webext-types

Then reference the package in the jsconfig.json next to your manifest.json:

{
  "compilerOptions": {
    "target": "es2022",
    "module": "esnext",
    "moduleResolution": "bundler",
    "checkJs": false,
    "lib": ["es2022", "dom"],
    "types": ["@thunderbirdops/webext-types"]
  },
  "include": ["**/*.js"]
}

Manifest V2 add-ons use "types": ["@thunderbirdops/webext-types/mv2"] instead.

Do not combine these typings with another package that declares browser or messenger, such as @types/firefox-webext-browser or @types/thunderbird-webext-browser.

Catch mistakes early

With the setup above you get completion and hover information. To also have mistakes reported in plain JavaScript, turn on error checking in one of two ways:

Either way, typos are reported while you type:

const page = await messenger.messages.list(folderId);
console.log(page.mesages);
// Property 'mesages' does not exist on type 'MessageList'.
// Did you mean 'messages'?

Event listeners also get the types of their parameters from the typings, so you do not have to declare them. The parameters folder and messages are known here, and mistakes on them are reported as well:

messenger.messages.onNewMailReceived.addListener(async (folder, messages) => {
  console.log(folder.nme);
  // Property 'nme' does not exist on type 'MailFolder'.
  // Did you mean 'name'?
});

Errors that are not about Thunderbird

When error checking is on, TypeScript also checks the rest of your JavaScript, and it can report problems that have nothing to do with the Thunderbird APIs. The typings only describe messenger.* and browser.*. Everything else, including the DOM, is described by TypeScript's own definitions. A common case:

const input = document.querySelector("#name");
console.log(input.value);
// Property 'value' does not exist on type 'Element'.

Which element has the id name is decided by your HTML page, and TypeScript does not read it. It only knows that querySelector returns an Element, which has no value. Either check the type in your code, or define it, and the error goes away.

Checking the type is safe, because the check also runs when your add-on runs:

const input = document.querySelector("#name");
if (!(input instanceof HTMLInputElement)) {
  throw new Error("#name is not an input");
}
console.log(input.value); // fine

Defining the type is shorter. A comment above the declaration tells TypeScript what the element is:

/** @type {HTMLInputElement} */
const input = document.querySelector("#name");
console.log(input.value); // fine

TypeScript trusts that comment without verifying it. If the element is not an input after all, you get no error here and the mistake only shows when the add-on runs.

Using TypeScript

Your add-on does not need to be written in TypeScript to use the typings. They are development tooling and are not needed at runtime. If you want to write your add-on in TypeScript, the typings work there as well, and all your files are checked. The TypeScript, Vue and Experiment API example shows a complete project, including how to compile it.

Source

The typings are generated by webext-typings-generator from webext-annotated-schemas.