Best Practices
Enable JSDoc Linting
ESLint supports linting of JSDoc comments. Enabling the rules on your component will help to ensure that you avoid missing or incorrect type definitions for function parameters.
You can check if your component is already covered by ensuring it is not in the
rollout-valid-jsdoc or rollout-require-jsdoc sections of the
eslint-rollouts.config.mjs
file in the top level of firefox-main.
Documenting Types
Avoid Missing Type Annotations
By default, if no type annotation is given and it cannot be inferred, then
TypeScript will assign that variable the any type. This is a special type that
skips type checking, and therefore may cause hidden failures.
For class members and functions this means adding type definitions for all the parameters, e.g.
class Foo {
/**
* Stores the search string. The type here could be omitted if the property is assigned in
* the constructor of the class.
*
* @type {string}
*/
#search;
/**
* Details about the function.
*
* @param {string} searchString
* Param documentation.
* @param {object} previousResult
* Param documentation.
* @param {nsIAutoCompleteObserver} listener
* Param documentation.
*/
startSearch(searchString, previousResult, listener) {}
}
Variables
Variable types will be inferred from the item that they are initially assigned to. However, sometimes you may need to define the type appropriately, especially for sets and maps.
// This will be inferred as type string.
let foo = "bar";
// This needs the type defining.
/** @type {Map<string, number>} */
let baz = new Map();
baz.set("star", 1701);
Avoid object types
object types are treated much the same as any - there is no type checking
performed on them.
Ideally all types should be defined. There are two ways to do this.
The first is within JSDoc comments:
/**
* @typedef {object} submissionMapEntry
* @property {SearchEngine} engine
* The search engine.
* @property {string} termsParameterName
* The search term parameter name.
*/
/**
* Alternately for function parameters:
*
* @param {object} options
* @param {boolean} options.option1
* A required boolean property within options.
* @param {number} [options.option2]
* An optional number property within options.
*/
function myFunc(options) {}
This may then be used within the file.
The second way may be more appropriate if a type is used widely within a
component. You can create a types/urlbarType.d.ts file, reference it from the
tsconfig.json file and include a definition such as:
/**
* A structure that holds the details of commands for results.
*/
type UrlbarResultCommand = {
/**
* The name of the command. Must be specified unless `children` is present.
* When a command is picked, its name will be passed as `details.selType` to
* `onEngagement()`. The special name "separator" will create a menu separator.
*/
name?: string;
/**
* An l10n object for the command's label. Must be specified unless `name`
* is "separator".
*/
l10n?: L10nIdArgs;
/**
* If specified, a submenu will be created with the given child commands.
*/
children?: UrlbarResultCommand[];
};
Note
If you are sharing object types outside of your component, prefer using a proper class definition or other structure.
Import Types from Other Files
You may import types from other files to be able to reuse them.
/**
* @import { LangTags } from "./translations.d.ts"
*/
/**
* @import { OpenedConnection } from "resource://gre/modules/Sqlite.sys.mjs"
*/
A *.d.ts file is a special type-definition file for TypeScript. These should
generally only be used for types that are internal to your component and are
not exposed outside.
XPCOMUtils.declareLazy / defineLazy
These are newer functions that combine the existing XPCOMUtils functions into formats that are compatible with TypeScript.
Defining lazy objects with these functions provides the appropriate information
for TypeScript to be able to know the types on the lazy objects. Otherwise the
lazy objects will be defined as any.
Note
It is suggested that these are not generally used until the functions have been
moved to ChromeUtils,
to avoid needing to import XPCOMUtils everywhere.