From dceb47fb3ea99ad7cc4308fa2c9ecb0d012639e1 Mon Sep 17 00:00:00 2001 From: rebekahpotter Date: Mon, 26 Aug 2019 20:45:13 -0700 Subject: [PATCH] Update JS styleguide (#464) Update JS styleguide Closes #462. --- jsguide.html | 1627 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 1211 insertions(+), 416 deletions(-) diff --git a/jsguide.html b/jsguide.html index c931a69..8e414af 100644 --- a/jsguide.html +++ b/jsguide.html @@ -89,36 +89,19 @@ depending only on which makes the code easier to read and understandTip: In the Unicode escape case, and occasionally even when actual Unicode characters are used, an explanatory comment can be very helpful.

- - - - - - - - - -
Example - Discussion -
const units = 'μs'; - Best: perfectly clear even without a comment. -
- const units = '\u03bcs'; // 'μs' - - Allowed, but there’s no reason to do this. -
- const units = '\u03bcs'; // Greek letter mu, 's' - - Allowed, but awkward and prone to mistakes. -
const units = '\u03bcs'; - Poor: the reader has no idea what this is. -
- return '\ufeff' + content; // byte order mark - - - Good: use escapes for non-printable characters, and comment if - necessary. -
+
/* Best: perfectly clear even without a comment. */
+const units = 'μs';
+
+/* Allowed: but unncessary as μ is a printable character. */
+const units = '\u03bcs'; // 'μs'
+
+/* Good: use escapes for non-printable characters with a comment for clarity. */
+return '\ufeff' + content;  // Prepend a byte order mark.
+
+ +
/* Poor: the reader has no idea what character this is. */
+const units = '\u03bcs';
+

Tip: Never make your code less readable simply out of fear that some programs might not handle non-ASCII characters properly. If that happens, those programs @@ -126,13 +109,16 @@ are broken and they must be fixed.

3 Source file structure

-

A source file consists of, in order:

+

All new source files should either be a goog.module file (a file containing a +goog.module call) or an ECMAScript (ES) module (uses import and export +statements). Files consist of the following, in order:

  1. License or copyright information, if present
  2. @fileoverview JSDoc, if present
  3. -
  4. goog.module statement
  5. -
  6. goog.require statements
  7. +
  8. goog.module statement, if a goog.module file
  9. +
  10. ES import statements, if an ES module
  11. +
  12. goog.require and goog.requireType statements
  13. The file’s implementation
@@ -149,9 +135,9 @@ file's implementation, which may be preceded by 1 or 2 blank lines.

3.3 goog.module statement

-

All files must declare exactly one goog.module name on a single line: lines -containing a goog.module declaration must not be wrapped, and are therefore an -exception to the 80-column limit.

+

All goog.module files must declare exactly one goog.module name on a single +line: lines containing a goog.module declaration must not be wrapped, and are +therefore an exception to the 80-column limit.

The entire argument to goog.module is what defines a namespace. It is the package name (an identifier that reflects the fragment of the directory @@ -168,7 +154,7 @@ that it defines concatenated to the end.

Module namespaces may never be named as a direct child of another module's namespace.

-

Illegal:

+

Disallowed:

goog.module('foo.bar');   // 'foo.bar.qux' would be fine, though
 goog.module('foo.bar.baz');
@@ -179,12 +165,7 @@ children are subdirectories of higher-level parent directories.  Note that this
 implies that owners of “parent” namespace groups are necessarily aware of all
 child namespaces, since they exist in the same directory.

-

3.3.2 goog.setTestOnly

- -

The single goog.module statement may optionally be followed by a call to -goog.setTestOnly().

- -

3.3.3 goog.module.declareLegacyNamespace

+

3.3.2 goog.module.declareLegacyNamespace

The single goog.module statement may optionally be followed by a call to goog.module.declareLegacyNamespace();. Avoid @@ -205,29 +186,415 @@ namespace, this name must not be a child or parent of any other goog.module('parent.child'); cannot both exist safely, nor can goog.module('parent'); and goog.module('parent.child.grandchild');).

-

3.3.4 ES6 Modules

+

3.3.3 goog.module Exports

-

Do not use ES6 modules yet (i.e. the export and import keywords), as their -semantics are not yet finalized. Note that this policy will be revisited once -the semantics are fully-standard.

+

Classes, enums, functions, constants, and other symbols are exported using the +exports object. Exported symbols may be defined directly on the exports +object, or else declared locally and exported separately. Symbols are only +exported if they are meant to be used outside the module. Non-exported +module-local symbols are not declared @private nor do their names end with an +underscore. There is no prescribed ordering for exported and module-local +symbols.

-

3.4 goog.require statements

+

Examples:

-

Imports are done with goog.require statements, grouped together immediately -following the module declaration. Each goog.require is assigned to a single -constant alias, or else destructured into several constant aliases. These -aliases are the only acceptable way to refer to the required dependency, -whether in code or in type annotations: the fully qualified name is never used -except as the argument to goog.require. Alias names should match the final -dot-separated component of the imported module name when possible, though -additional components may be included (with appropriate casing such that the -alias' casing still correctly identifies its type) if necessary to -disambiguate, or if it significantly improves readability. goog.require -statements may not appear anywhere else in the file.

+
const /** !Array<number> */ exportedArray = [1, 2, 3];
 
-

If a module is imported only for its side effects, the assignment may be -omitted, but the fully qualified name may not appear anywhere else in the file. -A comment is required to explain why this is needed and suppress a compiler +const /** !Array<number> */ moduleLocalArray = [4, 5, 6]; + +/** @return {number} */ +function moduleLocalFunction() { + return moduleLocalArray.length; +} + +/** @return {number} */ +function exportedFunction() { + return moduleLocalFunction() * 2; +} + +exports = {exportedArray, exportedFunction}; +

+ +
/** @const {number} */
+exports.CONSTANT_ONE = 1;
+
+/** @const {string} */
+exports.CONSTANT_TWO = 'Another constant';
+
+ +

Do not annotate the exports object as @const as it is already treated as a +constant by the compiler.

+ +
/** @const */
+exports = {exportedFunction};
+
+ +

+ +

3.4 ES modules

+ +

+ +

3.4.1 Imports

+ +

Import statements must not be line wrapped and are therefore an exception to the +80-column limit.

+ +

+ +
3.4.1.1 Import paths
+ +

ES module files must use the import statement to import other ES module +files. Do not goog.require another ES module.

+ +
import './sideeffects.js';
+
+import * as goog from '../closure/goog/goog.js';
+import * as parent from '../parent.js';
+
+import {name} from './sibling.js';
+
+ +

+ +
3.4.1.1.1 File extensions in import paths
+ +

The .js file extension is not optional in import paths and must always be +included.

+ +
import '../directory/file';
+
+ +
import '../directory/file.js';
+
+ +
3.4.1.2 Importing the same file multiple times
+ +

Do not import the same file multiple times. This can make it hard to determine +the aggregate imports of a file.

+ +
// Imports have the same path, but since it doesn't align it can be hard to see.
+import {short} from './long/path/to/a/file.js';
+import {aLongNameThatBreaksAlignment} from './long/path/to/a/file.js';
+
+ +

+ +
3.4.1.3 Naming imports
+ +
3.4.1.3.1 Naming module imports
+ +

Module import names (import * as name) are lowerCamelCase names that are +derived from the imported file name.

+ +
import * as fileOne from '../file-one.js';
+import * as fileTwo from '../file_two.js';
+import * as fileThree from '../filethree.js';
+
+ +
import * as libString from './lib/string.js';
+import * as math from './math/math.js';
+import * as vectorMath from './vector/math.js';
+
+ +
3.4.1.3.2 Naming default imports
+ +

Default import names are derived from the imported file name and follow the +rules in ??.

+ +
import MyClass from '../my-class.js';
+import myFunction from '../my_function.js';
+import SOME_CONSTANT from '../someconstant.js';
+
+ +

Note: In general this should not happen as default exports are banned by this +style guide, see ??. Default imports are only used +to import modules that do not conform to this style guide.

+ +
3.4.1.3.3 Naming named imports
+ +

In general symbols imported via the named import (import {name}) should keep +the same name. Avoid aliasing imports (import {SomeThing as SomeOtherThing}). +Prefer fixing name collisions by using a module import (import *) or renaming +the exports themselves.

+ +
import * as bigAnimals from './biganimals.js';
+import * as domesticatedAnimals from './domesticatedanimals.js';
+
+new bigAnimals.Cat();
+new domesticatedAnimals.Cat();
+
+ +

If renaming a named import is needed then use components of the imported +module's file name or path in the resulting alias.

+ +
import {Cat as BigCat} from './biganimals.js';
+import {Cat as DomesticatedCat} from './domesticatedanimals.js';
+
+new BigCat();
+new DomesticatedCat();
+
+ +

+ +

3.4.2 Exports

+ +

Symbols are only exported if they are meant to be used outside the module. +Non-exported module-local symbols are not declared @private nor do their names +end with an underscore. There is no prescribed ordering for exported and +module-local symbols.

+ +
3.4.2.1 Named vs default exports
+ +

Use named exports in all code. You can apply the export keyword to a +declaration, or use the export {name}; syntax.

+ +

Do not use default exports. Importing modules must give a name to these values, +which can lead to inconsistencies in naming across modules.

+ +
// Do not use default exports:
+export default class Foo { ... } // BAD!
+
+ +
// Use named exports:
+export class Foo { ... }
+
+ +
// Alternate style named exports:
+class Foo { ... }
+
+export {Foo};
+
+ +
3.4.2.2 Exporting static container classes and objects
+ +

Do not export container classes or objects with static methods or properties for +the sake of namespacing.

+ +
// container.js
+// Bad: Container is an exported class that has only static methods and fields.
+export class Container {
+  /** @return {number} */
+  static bar() {
+    return 1;
+  }
+}
+
+/** @const {number} */
+Container.FOO = 1;
+
+ +

Instead, export individual constants and functions:

+ +
/** @return {number} */
+export function bar() {
+  return 1;
+}
+
+export const /** number */ FOO = 1;
+
+ +

+ +
3.4.2.3 Mutability of exports
+ +

Exported variables must not be mutated outside of module initialization.

+ +

There are alternatives if mutation is needed, including exporting a constant +reference to an object that has mutable fields or exporting accessor functions for +mutable data.

+ +
// Bad: both foo and mutateFoo are exported and mutated.
+export let /** number */ foo = 0;
+
+/**
+ * Mutates foo.
+ */
+export function mutateFoo() {
+  ++foo;
+}
+
+/**
+ * @param {function(number): number} newMutateFoo
+ */
+export function setMutateFoo(newMutateFoo) {
+  // Exported classes and functions can be mutated!
+  mutateFoo = () => {
+    foo = newMutateFoo(foo);
+  };
+}
+
+ +
// Good: Rather than export the mutable variables foo and mutateFoo directly,
+// instead make them module scoped and export a getter for foo and a wrapper for
+// mutateFooFunc.
+let /** number */ foo = 0;
+let /** function(number): number */ mutateFooFunc = foo => foo + 1;
+
+/** @return {number} */
+export function getFoo() {
+  return foo;
+}
+
+export function mutateFoo() {
+  foo = mutateFooFunc(foo);
+}
+
+/** @param {function(number): number} mutateFoo */
+export function setMutateFoo(mutateFoo) {
+  mutateFooFunc = mutateFoo;
+}
+
+ +

+ +
3.4.2.4 export from
+ +

export from statements must not be line wrapped and are therefore an +exception to the 80-column limit. This applies to both export from flavors.

+ +
export {specificName} from './other.js';
+export * from './another.js';
+
+ +

3.4.3 Circular Dependencies in ES modules

+ +

Do not create cycles between ES modules, even though the ECMAScript +specification allows this. Note that it is possible to create cycles with both +the import and export statements.

+ +
// a.js
+import './b.js';
+
+ +
// b.js
+import './a.js';
+
+// `export from` can cause circular dependencies too!
+export {x} from './c.js';
+
+ +
// c.js
+import './b.js';
+
+export let x;
+
+ +

+ +

3.4.4 Interoperating with Closure

+ +

+ +
3.4.4.1 Referencing goog
+ +

To reference the Closure goog namespace, import Closure's goog.js.

+ +
import * as goog from '../closure/goog/goog.js';
+
+const name = goog.require('a.name');
+
+export const CONSTANT = name.compute();
+
+ +

goog.js exports only a subset of properties from the global goog that can be +used in ES modules.

+ +

+ +
3.4.4.2 goog.require in ES modules
+ +

goog.require in ES modules works as it does in goog.module files. You can +require any Closure namespace symbol (i.e., symbols created by goog.provide or +goog.module) and goog.require will return the value.

+ +
import * as goog from '../closure/goog/goog.js';
+import * as anEsModule from './anEsModule.js';
+
+const GoogPromise = goog.require('goog.Promise');
+const myNamespace = goog.require('my.namespace');
+
+ +

+ +
3.4.4.3 Declaring Closure Module IDs in ES modules
+ +

goog.declareModuleId can be used within ES modules to declare a +goog.module-like module ID. This means that this module ID can be +goog.required, goog.module.getd, goog.forwardDeclare'd, etc. as if it were +a goog.module that did not call goog.module.declareLegacyNamespace. It does +not create the module ID as a globally available JavaScript symbol.

+ +

A goog.require (or goog.module.get) for a module ID from +goog.declareModuleId will always return the module object (as if it was +import *'d). As a result, the argument to goog.declareModuleId should always +end with a lowerCamelCaseName.

+ +

Note: It is an error to call goog.module.declareLegacyNamespace in an ES +module, it can only be called from goog.module files. There is no direct way +to associate a legacy namespace with an ES module.

+ +

goog.declareModuleId should only be used to upgrade Closure files to ES +modules in place, where named exports are used.

+ +
import * as goog from '../closure/goog.js';
+
+goog.declareModuleId('my.esm');
+
+export class Class {};
+
+ +

3.5 goog.setTestOnly

+ +

In a goog.module file the goog.module statement may optionally be followed +by a call to goog.setTestOnly().

+ +

In an ES module the import statements may optionally be followed by a call to +goog.setTestOnly().

+ +

3.6 goog.require and goog.requireType statements

+ +

Imports are done with goog.require and goog.requireType statements. The +names imported by a goog.require statement may be used both in code and in +type annotations, while those imported by a goog.requireType may be used +in type annotations only.

+ +

The goog.require and goog.requireType statements form a contiguous block +with no empty lines. This block follows the goog.module declaration separated +by a single empty line. The entire argument to +goog.require or goog.requireType is a namespace defined by a goog.module +in a separate file. goog.require and goog.requireType statements may not +appear anywhere else in the file.

+ +

Each goog.require or goog.requireType is assigned to a single constant +alias, or else destructured into several constant aliases. These aliases are the +only acceptable way to refer to dependencies in type annotations or code. Fully +qualified namespaces must not be used anywhere, except as an argument to +goog.require or goog.requireType.

+ +

Exception: Types, variables, and functions declared in externs files have to +use their fully qualified name in type annotations and code.

+ +

Aliases must match the final dot-separated component of the imported module's +namespace.

+ +

Exception: In certain cases, additional components of the namespace can be +used to form a longer alias. The resulting alias must retain the original +identifier's casing such that it still correctly identifies its type. Longer +aliases may be used to disambiguate otherwise identical aliases, or if it +significantly improves readability. In addition, a longer alias must be used to +prevent masking native types such as Element, Event, Error, Map, and +Promise (for a more complete list, see Standard Built-in Objects and Web +APIs at MDN). When renaming destructured aliases, a space must follow the colon +as required in ??.

+ +

A file should not contain both a goog.require and a goog.requireType +statement for the same namespace. If the imported name is used both in code and +in type annotations, it should be imported by a single goog.require statement.

+ +

If a module is imported only for its side effects, the call must be a +goog.require (not a goog.requireType) and assignment may be omitted. A +comment is required to explain why this is needed and suppress a compiler warning.

@@ -235,51 +602,83 @@ warning.

The lines are sorted according to the following rules: All requires with a name on the left hand side come first, sorted alphabetically by those names. Then destructuring requires, again sorted by the names on the left hand side. -Finally, any goog.require calls that are standalone (generally these are for -modules imported just for their side effects).

+Finally, any require calls that are standalone (generally these are for modules +imported just for their side effects).

Tip: There’s no need to memorize this order and enforce it manually. You can rely on your IDE to report requires that are not sorted correctly.

If a long alias or module name would cause a line to exceed the 80-column limit, -it must not be wrapped: goog.require lines are an exception to the 80-column +it must not be wrapped: require lines are an exception to the 80-column limit.

Example:

-
const MyClass = goog.require('some.package.MyClass');
+
// Standard alias style.
+const MyClass = goog.require('some.package.MyClass');
+const MyType = goog.requireType('some.package.MyType');
+// Namespace-based alias used to disambiguate.
 const NsMyClass = goog.require('other.ns.MyClass');
-const googAsserts = goog.require('goog.asserts');
+// Namespace-based alias used to prevent masking native type.
+const RendererElement = goog.require('web.renderer.Element');
+// Out of sequence namespace-based aliases used to improve readability.
+// Also, require lines longer than 80 columns must not be wrapped.
+const SomeDataStructureModel = goog.requireType('identical.package.identifiers.models.SomeDataStructure');
+const SomeDataStructureProto = goog.require('proto.identical.package.identifiers.SomeDataStructure');
+// Standard alias style.
+const asserts = goog.require('goog.asserts');
+// Namespace-based alias used to disambiguate.
 const testingAsserts = goog.require('goog.testing.asserts');
-const than80columns = goog.require('pretend.this.is.longer.than80columns');
-const {clear, forEach, map} = goog.require('goog.array');
+// Standard destructuring into aliases.
+const {clear, clone} = goog.require('goog.array');
+const {Rgb} = goog.require('goog.color');
+// Namespace-based destructuring into aliases in order to disambiguate.
+const {SomeType: FooSomeType} = goog.requireType('foo.types');
+const {clear: objectClear, clone: objectClone} = goog.require('goog.object');
+// goog.require without an alias in order to trigger side effects.
 /** @suppress {extraRequire} Initializes MyFramework. */
 goog.require('my.framework.initialization');
 
-

Illegal:

+

Discouraged:

-
const randomName = goog.require('something.else'); // name must match
+
// If necessary to disambiguate, prefer PackageClass over SomeClass as it is
+// closer to the format of the module name.
+const SomeClass = goog.require('some.package.Class');
+
-const {clear, forEach, map} = // don't break lines - goog.require('goog.array'); +

Disallowed:

-function someFunction() { - const alias = goog.require('my.long.name.alias'); // must be at top level - // … +
// Extra terms must come from the namespace.
+const MyClassForBizzing = goog.require('some.package.MyClass');
+// Alias must include the entire final namespace component.
+const MyClass = goog.require('some.package.MyClassForBizzing');
+// Alias must not mask native type (should be `const JspbMap` here).
+const Map = goog.require('jspb.Map');
+// Don't break goog.require lines over 80 columns.
+const SomeDataStructure =
+    goog.require('proto.identical.package.identifiers.SomeDataStructure');
+// Alias must be based on the namespace.
+const randomName = goog.require('something.else');
+// Missing a space after the colon.
+const {Foo:FooProto} = goog.require('some.package.proto.Foo');
+// goog.requireType without an alias.
+goog.requireType('some.package.with.a.Type');
+
+
+/**
+ * @param {!some.unimported.Dependency} param All external types used in JSDoc
+ *     annotations must be goog.require'd, unless declared in externs.
+ */
+function someFunction(param) {
+  // goog.require lines must be at the top level before any other code.
+  const alias = goog.require('my.long.name.alias');
+  // ...
 }
 
-

3.4.1 goog.forwardDeclare

- -

goog.forwardDeclare is not needed very often, but is a valuable tool to break -circular dependencies or to reference late loaded code. These statements are -grouped together and immediately follow any goog.require statements. A -goog.forwardDeclare statement must follow the same style rules as a -goog.require statement.

- -

3.5 The file’s implementation

+

3.7 The file’s implementation

The actual implementation follows after all dependency information is declared (separated by at least one blank line).

@@ -308,7 +707,7 @@ editors.

while, as well as any others), even if the body contains only a single statement. The first statement of a non-empty block must begin on its own line.

-

Illegal:

+

Disallowed:

if (someVeryLongCondition())
   doSomething();
@@ -321,7 +720,7 @@ no wrapping (and that doesn’t have an else) may be kept on a single line w
 braces when it improves readability.  This is the only case in which a control
 structure may omit braces and newlines.

-
if (shortCondition()) return;
+
if (shortCondition()) foo();
 

4.1.2 Nonempty blocks: K&R style

@@ -370,7 +769,7 @@ multiple blocks: if/else or try/cat
function doNothing() {}
 
-

Illegal:

+

Disallowed:

if (condition) {
   // …
@@ -557,16 +956,25 @@ line that would exceed this limit must be line-wrapped, as explained in
 

Exceptions:

    -
  1. Lines where obeying the column limit is not possible (for example, a long URL -in JSDoc or a shell command intended to be copied-and-pasted).
  2. -
  3. goog.module and goog.require statements (see ?? and -??).
  4. +
  5. goog.module, goog.require and goog.requireType statements (see +?? and ??).
  6. +
  7. ES module import and export from statements (see +?? and ??).
  8. +
  9. Lines where obeying the column limit is not possible or would hinder +discoverability. Examples include: +
      +
    • A long URL which should be clickable in source.
    • +
    • A shell command intended to be copied-and-pasted.
    • +
    • A long string literal which may need to be copied or searched for wholly +(e.g., a long file path).
    • +

4.5 Line-wrapping

-

Terminology Note: Line-wrapping is defined as breaking a single expression -into multiple lines.

+

Terminology Note: Line wrapping is breaking a chunk of code into multiple +lines to obey column limit, where the chunk could otherwise legally fit in a +single line.

There is no comprehensive, deterministic formula showing exactly how to line-wrap in every situation. Very often there are several valid ways to @@ -588,13 +996,13 @@ level.

currentEstimate =
     calc(currentEstimate + x * currentEstimate) /
-        2.0f;
+        2.0;
 

Discouraged:

currentEstimate = calc(currentEstimate + x *
-    currentEstimate) / 2.0f;
+    currentEstimate) / 2.0;
 

In the preceding example, the syntactic levels from highest to lowest are as @@ -669,26 +1077,28 @@ literals, comments, and JSDoc, a single internal ASCII space also appears in the following places only.

    -
  1. Separating any reserved word (such as if, for, or catch) from an open -parenthesis (() that follows it on that line.
  2. +
  3. Separating any reserved word (such as if, for, or catch) except for +function and super, from an open parenthesis (() that follows it on +that line.
  4. Separating any reserved word (such as else or catch) from a closing curly brace (}) that precedes it on that line.
  5. Before any open curly brace ({), with two exceptions:
    1. Before an object literal that is the first argument of a function or the first element in an array literal (e.g. foo({a: [{c: d}]})).
    2. -
    3. In a template expansion, as it is forbidden by the language -(e.g. abc${1 + 2}def).
    4. +
    5. In a template expansion, as it is forbidden by the language (e.g. valid: +`ab${1 + 2}cd`, invalid: `xy$ {3}z`).
  6. On both sides of any binary or ternary operator.
  7. After a comma (,) or semicolon (;). Note that spaces are never allowed before these characters.
  8. After the colon (:) in an object literal.
  9. -
  10. On both sides of the double slash (//) that begins an end-of-line -comment. Here, multiple spaces are allowed, but not required.
  11. -
  12. After an open-JSDoc comment character and on both sides of close characters -(e.g. for short-form type declarations or casts: this.foo = /** @type -{number} */ (bar); or function(/** string */ foo) {).
  13. +
  14. On both sides of the double slash (//) that begins an end-of-line comment. +Here, multiple spaces are allowed, but not required.
  15. +
  16. After an open-block comment character and on both sides of close characters +(e.g. for short-form type declarations, casts, and parameter name comments: +this.foo = /** @type {number} */ (bar); or function(/** string */ foo) +{; or baz(/* buzz= */ true)).

4.6.3 Horizontal alignment: discouraged

@@ -778,9 +1188,7 @@ in ??.

Block comments are indented at the same level as the surrounding code. They may be in /* … */ or //-style. For multi-line /* … */ comments, subsequent lines must start with * aligned with the * on the previous line, to make -comments obvious with no extra context. “Parameter name” comments should appear -after values whenever the value and method name do not sufficiently convey the -meaning.

+comments obvious with no extra context.

/*
  * This is
@@ -791,13 +1199,27 @@ meaning.

// is this. /* This is fine, too. */ - -someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);

Comments are not enclosed in boxes drawn with asterisks or other characters.

-

Do not use JSDoc (/** … */) for any of the above implementation comments.

+

Do not use JSDoc (/** … */) for implementation comments.

+ +

4.8.2 Parameter Name Comments

+ +

“Parameter name” comments should be used whenever the value and method name do +not sufficiently convey the meaning, and refactoring the method to be clearer is +infeasible . +Their preferred format is before the value with =:

+ +
someFunction(obviousParam, /* shouldRender= */ true, /* name= */ 'hello');
+
+ +

For consistency with surrounding code you may put them after the value without +=:

+ +
someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);
+

5 Language features

@@ -827,16 +1249,26 @@ the point they are first used (within reason), to minimize their scope.

5.1.4 Declare types as needed

JSDoc type annotations may be added either on the line above the declaration, or -else inline before the variable name.

+else inline before the variable name if no other JSDoc is present.

Example:

const /** !Array<number> */ data = [];
 
-/** @type {!Array<number>} */
+/**
+ * Some description.
+ * @type {!Array<number>}
+ */
 const data = [];
 
+

Mixing inline and JSDoc styles is not allowed: the compiler will only process +the first JsDoc and the inline annotations will be lost.

+ +
/** Some description. */
+const /** !Array<number> */ data = [];
+
+

Tip: There are many cases where the compiler can infer a templatized type but not its parameters. This is particularly the case when the initializing literal or constructor call does not include any values of the template parameter type @@ -866,7 +1298,7 @@ element and the closing bracket.

The constructor is error-prone if arguments are added or removed. Use a literal instead.

-

Illegal:

+

Disallowed:

const a1 = new Array(x1, x2, x3);
 const a2 = new Array(x1, x2);
@@ -915,14 +1347,14 @@ hand side:

function optionalDestructuring([a = 4, b = 2] = []) { … };
-

Illegal:

+

Disallowed:

function badDestructuring([a, b] = [4, 2]) { … };
 

Tip: For (un)packing multiple values into a function’s parameter or return, prefer object destructuring to array destructuring when possible, as it allows -naming the individual elements and specifying a different type for each.*

+naming the individual elements and specifying a different type for each.

5.2.5 Spread operator

@@ -956,11 +1388,33 @@ instead.

symbols) or dicts (with quoted and/or computed keys). Do not mix these key types in a single object literal.

-

Illegal:

+

Disallowed:

{
-  a: 42, // struct-style unquoted key
-  'b': 43, // dict-style quoted key
+  width: 42, // struct-style unquoted key
+  'maxWidth': 43, // dict-style quoted key
+}
+
+ +

This also extends to passing the property name to functions, like +hasOwnProperty. In particular, doing so will break in compiled code because +the compiler cannot rename/obfuscate the string literal.

+ +

Disallowed:

+ +
/** @type {{width: number, maxWidth: (number|undefined)}} */
+const o = {width: 42};
+if (o.hasOwnProperty('maxWidth')) {
+  ...
+}
+
+ +

This is best implemented as:

+ +
/** @type {{width: number, maxWidth: (number|undefined)}} */
+const o = {width: 42};
+if (o.maxWidth != null) {
+  ...
 }
 
@@ -968,9 +1422,10 @@ types in a single object literal.

Computed property names (e.g., {['key' + foo()]: 42}) are allowed, and are considered dict-style (quoted) keys (i.e., must not be mixed with non-quoted -keys) unless the computed property is a symbol (e.g., [Symbol.iterator]). -Enum values may also be used for computed keys, but should not be mixed with -non-enum keys in the same literal.

+keys) unless the computed property is a +symbol +(e.g., [Symbol.iterator]). Enum values may also be used for computed keys, but +should not be mixed with non-enum keys in the same literal.

5.3.5 Method shorthand

@@ -1046,7 +1501,7 @@ by the compiler).

function destructured(ordinary, {num, str = 'some default'} = {})
-

Illegal:

+

Disallowed:

/** @param {{x: {num: (number|undefined), str: (string|undefined)}}} param1 */
 function nestedTooDeeply({x: {num, str}}) {};
@@ -1093,17 +1548,18 @@ const Option = {
 
 

5.4.1 Constructors

-

Constructors are optional for concrete classes. Subclass constructors must call -super() before setting any fields or otherwise accessing this. Interfaces -must not define a constructor.

+

Constructors are optional. Subclass constructors must call super() before +setting any fields or otherwise accessing this. Interfaces should declare +non-method properties in the constructor.

5.4.2 Fields

Set all of a concrete object’s fields (i.e. all properties other than methods) in the constructor. Annotate fields that are never reassigned with @const -(these need not be deeply immutable). Private fields must be annotated with -@private and their names must end with a trailing underscore. Fields are never -set on a concrete class' prototype.

+(these need not be deeply immutable). Annotate non-public fields with the proper +visibility annotation (@private, @protected, @package), and end all +@private fields' names with an underscore. Fields are never set on a concrete +class' prototype.

Example:

@@ -1111,6 +1567,9 @@ set on a concrete class' prototype.

constructor() { /** @private @const {!Bar} */ this.bar_ = computeBar(); + + /** @protected @const {!Baz} */ + this.baz = computeBaz(); } }
@@ -1147,12 +1606,12 @@ either the constructor or a subclass constructor (and must be defined with @nocollapse if this is done), and must not be called directly on a subclass that doesn’t define the method itself.

-

Illegal:

+

Disallowed:

class Base { /** @nocollapse */ static foo() {} }
 class Sub extends Base {}
 function callFoo(cls) { cls.foo(); }  // discouraged: don't call static methods dynamically
-Sub.foo();  // illegal: don't call static methods on subclasses that don't define it themselves
+Sub.foo();  // Disallowed: don't call static methods on subclasses that don't define it themselves
 

5.4.5 Old-style class declarations

@@ -1228,31 +1687,28 @@ C.prototype.method = function(param) {

The class keyword allows clearer and more readable class definitions than defining prototype properties. Ordinary implementation code has no business -manipulating these objects, though they are still useful for defining @record -interfaces and classes as defined in ??. Mixins -and modifying the prototypes of builtin objects are -explicitly forbidden.

+manipulating these objects, though they are still useful for defining classes as +defined in ??. Mixins and modifying the +prototypes of builtin objects are explicitly forbidden.

Exception: Framework code (such as Polymer, or Angular) may need to use prototypes, and should not resort to even-worse workarounds to avoid doing so.

-

Exception: Defining fields in interfaces (see ??).

-

5.4.7 Getters and Setters

Do not use JavaScript getter and setter properties. They are potentially surprising and difficult to reason about, and have limited support in the compiler. Provide ordinary methods instead.

-

Exception: when working with data binding frameworks (such as Angular and -Polymer), getters and setters may be used sparingly. Note, however, that -compiler support is limited. When they are used, they must be defined either -with get foo() and set foo(value) in the class or object literal, or if that -is not possible, with Object.defineProperties. Do not use -Object.defineProperty, which interferes with property renaming. Getters +

Exception: there are situations where defining a getter or setter is +unavoidable (e.g. data binding frameworks such as Angular and Polymer, or for +compatibility with external APIs that cannot be adjusted). In these cases only, +getters and setters may be used with caution, provided they are defined with +the get and set shorthand method keywords or Object.defineProperties (not +Object.defineProperty, which interferes with property renaming). Getters must not change observable state.

-

Illegal:

+

Disallowed:

class Foo {
   get next() { return this.nextId++; }
@@ -1273,8 +1729,8 @@ exceptional conditions could lead to infinite loops.

with @record can be explicitly (i.e. via @implements) or implicitly implemented by a class or object literal.

-

All non-static method bodies on an interface must be empty blocks. Fields must -be defined after the interface body as stubs on the prototype.

+

All non-static method bodies on an interface must be empty blocks. Fields must +be declared as uninitialized members in the class constructor.

Example:

@@ -1283,6 +1739,11 @@ be defined after the interface body as stubs on the prototype.

* @record */ class Frobnicator { + constructor() { + /** @type {number} The number of attempts before giving up. */ + this.attempts; + } + /** * Performs the frobnication according to the given strategy. * @param {!FrobnicationStrategy} strategy @@ -1290,43 +1751,36 @@ class Frobnicator { frobnicate(strategy) {} } -/** @type {number} The number of attempts before giving up. */ -Frobnicator.prototype.attempts;
+

5.4.10 Abstract Classes

+ +

Use abstract classes when appropriate. Abstract classes and methods must be +annotated with @abstract. Do not use goog.abstractMethod. See abstract +classes and methods.

+

5.5 Functions

5.5.1 Top-level functions

-

Exported functions may be defined directly on the exports object, or else -declared locally and exported separately. Non-exported functions are encouraged -and should not be declared @private.

+

Top-level functions may be defined directly on the exports object, or else +declared locally and optionally exported. See ?? +for more on exports.

Examples:

-
/** @return {number} */
-function helperFunction() {
-  return 42;
-}
-/** @return {number} */
-function exportedFunction() {
-  return helperFunction() * 2;
-}
-/**
- * @param {string} arg
- * @return {number}
- */
-function anotherExportedFunction(arg) {
-  return helperFunction() / arg.length;
-}
-/** @const */
-exports = {exportedFunction, anotherExportedFunction};
+
/** @param {string} str */
+exports.processString = (str) => {
+  // Process the string.
+};
 
-
/** @param {string} arg */
-exports.foo = (arg) => {
-  // do some stuff ...
+
/** @param {string} str */
+const processString = (str) => {
+  // Process the string.
 };
+
+exports = {processString};
 

5.5.2 Nested functions and closures

@@ -1336,22 +1790,73 @@ function a name, it should be assigned to a local const.

5.5.3 Arrow functions

-

Arrow functions provide a concise syntax and fix a number of difficulties with -this. Prefer arrow functions over the function keyword, particularly for -nested functions (but see ??).

+

Arrow functions provide a concise function syntax and simplify scoping this +for nested functions. Prefer arrow functions over the function keyword, +particularly for nested functions (but see +??).

-

Prefer using arrow functions over f.bind(this), and especially over -goog.bind(f, this). Avoid writing const self = this. Arrow functions are -particularly useful for callbacks, which sometimes pass unexpected additional -arguments.

+

Prefer arrow functions over other this scoping approaches such as +f.bind(this), goog.bind(f, this), and const self = this. Arrow functions +are particularly useful for calling into callbacks as they permit explicitly +specifying which parameters to pass to the callback whereas binding will blindly +pass along all parameters.

-

The right-hand side of the arrow may be a single expression or a block. -Parentheses around the arguments are optional if there is only a single -non-destructured argument.

+

The left-hand side of the arrow contains zero or more parameters. Parentheses +around the parameters are optional if there is only a single non-destructured +parameter. When parentheses are used, inline parameter types may be specified +(see ??).

-

Tip: It is a good practice to use parentheses even for single-argument arrows, -since the code may still parse reasonably (but incorrectly) if the parentheses -are forgotten when an additional argument is added.

+

Tip: Always using parentheses even for single-parameter arrow functions can +avoid situations where adding parameters, but forgetting to add parentheses, may +result in parseable code which no longer works as intended.

+ +

The right-hand side of the arrow contains the body of the function. By default +the body is a block statement (zero or more statements surrounded by curly +braces). The body may also be an implicitly returned single expression if +either: the program logic requires returning a value, or the void operator +precedes a single function or method call (using void ensures undefined is +returned, prevents leaking values, and communicates intent). The single +expression form is preferred if it improves readability (e.g., for short or +simple expressions).

+ +

Examples:

+ +
/**
+ * Arrow functions can be documented just like normal functions.
+ * @param {number} numParam A number to add.
+ * @param {string} strParam Another number to add that happens to be a string.
+ * @return {number} The sum of the two parameters.
+ */
+const moduleLocalFunc = (numParam, strParam) => numParam + Number(strParam);
+
+// Uses the single expression syntax with `void` because the program logic does
+// not require returning a value.
+getValue((result) => void alert(`Got ${result}`));
+
+class CallbackExample {
+  constructor() {
+    /** @private {number} */
+    this.cachedValue_ = 0;
+
+    // For inline callbacks, you can use inline typing for parameters.
+    // Uses a block statement because the value of the single expression should
+    // not be returned and the expression is not a single function call.
+    getNullableValue((/** ?number */ result) => {
+      this.cachedValue_ = result == null ? 0 : result;
+    });
+  }
+}
+
+ +

Disallowed:

+ +
/**
+ * A function with no params and no returned value.
+ * This single expression body usage is illegal because the program logic does
+ * not require returning a value and we're missing the `void` operator.
+ */
+const moduleLocalFunc = () => anotherFunction();
+

5.5.4 Generators

@@ -1381,15 +1886,10 @@ class SomeClass { }
-

5.5.5 Parameters

+

5.5.5 Parameter and return types

-

Function parameters must be typed with JSDoc annotations in the JSDoc preceding -the function’s definition, except in the case of same-signature @overrides, -where all types are omitted.

- -

Parameter types may be specified inline, immediately before the parameter name -(as in (/** number */ foo, /** string */ bar) => foo + bar). Inline and -@param type annotations must not be mixed in the same function definition.

+

Function parameters and return types should usually be documented with JSDoc +annotations. See ?? for more information.

5.5.5.1 Default parameters
@@ -1398,8 +1898,9 @@ list. Optional parameters must include spaces on both sides of the equals operator, be named exactly like required parameters (i.e., not prefixed with opt_), use the = suffix in their JSDoc type, come after required parameters, and not use initializers that produce observable side effects. All optional -parameters must have a default value in the function declaration, even if that -value is undefined.

+parameters for concrete functions must have default values, even if that value +is undefined. In contrast to concrete functions, abstract and interface +methods must omit default parameter values.

Example:

@@ -1409,6 +1910,15 @@ value is undefined.

* @param {!Node=} node Another optional parameter. */ function maybeDoSomething(required, optional = '', node = undefined) {} + +/** @interface */ +class MyInterface { + /** + * Interface and abstract methods must omit default parameter values. + * @param {string=} optional + */ + someMethod(optional) {} +}

Use default parameters sparingly. Prefer destructuring (as in @@ -1443,18 +1953,12 @@ parameter arguments, which confusingly shadows the built-in name.

-

5.5.6 Returns

- -

Function return types must be specified in the JSDoc directly above the function -definition, except in the case of same-signature @overrides where all types -are omitted.

- -

5.5.7 Generics

+

5.5.6 Generics

Declare generic functions and methods when necessary with @template TYPE in -the JSDoc above the class definition.

+the JSDoc above the function or method definition.

-

5.5.8 Spread operator

+

5.5.7 Spread operator

Function calls may use the spread operator (...). Prefer the spread operator to Function.prototype.apply when an array or iterable is unpacked into @@ -1478,13 +1982,13 @@ string to avoid having to escape the quote.

Ordinary string literals may not span multiple lines.

-

5.6.2 Template strings

+

5.6.2 Template literals

-

Use template strings (delimited with `) over complex string +

Use template literals (delimited with `) over complex string concatenation, particularly if multiple string literals are involved. Template -strings may span multiple lines.

+literals may span multiple lines.

-

If a template string spans multiple lines, it does not need to follow the +

If a template literal spans multiple lines, it does not need to follow the indentation of the enclosing block, though it may if the added whitespace does not matter.

@@ -1506,7 +2010,7 @@ with a backslash) in either ordinary or template string literals. Even though ES5 allows this, it can lead to tricky errors if any trailing whitespace comes after the slash, and is less obvious to readers.

-

Illegal:

+

Disallowed:

const longString = 'This is a very long string that far exceeds the 80 \
     column limit. It unfortunately contains long stretches of spaces due \
@@ -1547,6 +2051,9 @@ exceptional cases occur.  Always throw Errors or subclasses of new when constructing an
 Error.

+

This treatment extends to Promise rejection values as Promise.reject(obj) is +equivalent to throw obj; in async functions.

+

Custom exceptions provide a great way to convey additional error information from functions. They should be defined and used wherever the native Error type is insufficient.

@@ -1569,13 +2076,13 @@ reason this is justified is explained in a comment.

return handleTextResponse(response);
-

Illegal:

+

Disallowed:

-
   try {
+
  try {
     shouldFail();
     fail('expected an error');
+  } catch (expected) {
   }
-  catch (expected) {}
 

Tip: Unlike in some other languages, patterns like the above simply don’t work @@ -1612,36 +2119,51 @@ statement group of the switch block.

5.8.3.2 The default case is present

Each switch statement includes a default statement group, even if it contains -no code.

+no code. The default statement group must be last.

5.9 this

-

Only use this in class constructors and methods, or in arrow functions defined -within class constructors and methods. Any other uses of this must have an -explicit @this declared in the immediately-enclosing function’s JSDoc.

+

Only use this in class constructors and methods, in arrow functions defined +within class constructors and methods, or in functions that have an explicit +@this declared in the immediately-enclosing function’s JSDoc.

Never use this to refer to the global object, the context of an eval, the target of an event, or unnecessarily call()ed or apply()ed functions.

-

5.10 Disallowed features

+

5.10 Equality Checks

-

5.10.1 with

+

Use identity operators (===/!==) except in the cases documented below.

+ +

5.10.1 Exceptions Where Coercion is Desirable

+ +

Catching both null and undefined values:

+ +
if (someObjectOrPrimitive == null) {
+  // Checking for null catches both null and undefined for objects and
+  // primitives, but does not catch other falsy values like 0 or the empty
+  // string.
+}
+
+ +

5.11 Disallowed features

+ +

5.11.1 with

Do not use the with keyword. It makes your code harder to understand and has been banned in strict mode since ES5.

-

5.10.2 Dynamic code evaluation

+

5.11.2 Dynamic code evaluation

Do not use eval or the Function(...string) constructor (except for code loaders). These features are potentially dangerous and simply do not work in CSP environments.

-

5.10.3 Automatic semicolon insertion

+

5.11.3 Automatic semicolon insertion

Always terminate statements with semicolons (except function and class declarations, as noted above).

-

5.10.4 Non-standard features

+

5.11.4 Non-standard features

Do not use non-standard features. This includes old features that have been removed (e.g., WeakMap.clear), new features that are not yet standardized @@ -1653,12 +2175,12 @@ Chrome extensions or Node.js, can obviously use those APIs). Non-standard language “extensions” (such as those provided by some external transpilers) are forbidden.

-

5.10.5 Wrapper objects for primitive types

+

5.11.5 Wrapper objects for primitive types

Never use new on the primitive object wrappers (Boolean, Number, String, Symbol), nor include them in type annotations.

-

Illegal:

+

Disallowed:

const /** Boolean */ x = new Boolean(false);
 if (x) alert(typeof x);  // alerts 'object' - WAT?
@@ -1673,7 +2195,7 @@ using + or concatenating the empty string) or creating symbols.

if (!x) alert(typeof x); // alerts 'boolean', as expected
-

5.10.6 Modifying builtin objects

+

5.11.6 Modifying builtin objects

Never modify builtin types, either by adding methods to their constructors or to their prototypes. Avoid depending on libraries that do this. Note that the @@ -1683,6 +2205,27 @@ possible; nothing else may modify builtin objects.

Do not add symbols to the global object unless absolutely necessary (e.g. required by a third-party API).

+

5.11.7 Omitting () when invoking a constructor

+ +

Never invoke a constructor in a new statement without using parentheses ().

+ +

Disallowed:

+ +
new Foo;
+
+ +

Use instead:

+ +
new Foo();
+
+ +

Omitting parentheses can lead to subtle mistakes. These two lines are not +equivalent:

+ +
new Foo().Bar();
+new Foo.Bar();
+
+

6 Naming

6.1 Rules common to all identifiers

@@ -1697,20 +2240,21 @@ understandable by a new reader. Do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.

-
priceCountReader      // No abbreviation.
-numErrors             // "num" is a widespread convention.
-numDnsConnections     // Most people know what "DNS" stands for.
+
errorCount          // No abbreviation.
+dnsConnectionIndex  // Most people know what "DNS" stands for.
+referrerUrl         // Ditto for "URL".
+customerId          // "Id" is both ubiquitous and unlikely to be misunderstood.
 
-

Illegal:

+

Disallowed:

-
n                     // Meaningless.
-nErr                  // Ambiguous abbreviation.
-nCompConns            // Ambiguous abbreviation.
-wgcConnections        // Only your group knows what this stands for.
-pcReader              // Lots of things can be abbreviated "pc".
-cstmrId               // Deletes internal letters.
-kSecondsPerDay        // Do not use Hungarian notation.
+
n                   // Meaningless.
+nErr                // Ambiguous abbreviation.
+nCompConns          // Ambiguous abbreviation.
+wgcConnections      // Only your group knows what this stands for.
+pcReader            // Lots of things can be abbreviated "pc".
+cstmrId             // Deletes internal letters.
+kSecondsPerDay      // Do not use Hungarian notation.
 

6.2 Rules by identifier type

@@ -1732,8 +2276,8 @@ sometimes be adjectives or adjective phrases instead (for example, Readabl

6.2.3 Method names

-

Method names are written in lowerCamelCase. Private methods’ names must end -with a trailing underscore.

+

Method names are written in lowerCamelCase. Names for @private methods must +end with a trailing underscore.

Method names are typically verbs or verb phrases. For example, sendMessage or stop_. Getter and setter methods for properties are never required, but if @@ -1741,9 +2285,9 @@ they are used they should be named getFoo (or optionally isFo for booleans), or setFoo(value) for setters.

Underscores may also appear in JsUnit test method names to separate logical -components of the name. One typical pattern is test<MethodUnderTest>_<state>, -for example testPop_emptyStack. There is no One Correct Way to name test -methods.

+components of the name. One typical pattern is +test<MethodUnderTest>_<state>_<expectedOutcome>, for example +testPop_emptyStack_throws. There is no One Correct Way to name test methods.

6.2.4 Enum names

@@ -1776,9 +2320,9 @@ const NUMBER = 5; // Not constants let letVariable = 'non-const'; -class MyClass { constructor() { /** @const */ this.nonStatic = 'non-static'; } }; +class MyClass { constructor() { /** @const {string} */ this.nonStatic = 'non-static'; } }; /** @type {string} */ MyClass.staticButMutable = 'not @const, can be reassigned'; -const /** Set<String> */ mutableCollection = new Set(); +const /** Set<string> */ mutableCollection = new Set(); const /** ImmutableSet<SomeMutableType> */ mutableElements = ImmutableSet.of(mutable); const Foo = goog.require('my.Foo'); // mirrors imported name const logger = log.getLogger('loggers.are.not.immutable'); @@ -1786,7 +2330,7 @@ const logger = log.getLogger('loggers.are.not.immutable');

Constants’ names are typically nouns or noun phrases.

-
6.2.5.1 Local aliases
+
6.2.5.2 Local aliases

Local aliases should be used whenever they improve readability over fully-qualified names. Follow the same rules as goog.requires @@ -1822,15 +2366,21 @@ begin with a $. This exception does not apply to any other identif

6.2.8 Local variable names

Local variable names are written in lowerCamelCase, except for module-local -(top-level) constants, as described above. Constants in function scopes are -still named in lowerCamelCase. Note that lowerCamelCase applies even if the -variable holds a constructor.

+(top-level) constants, as described above. Constants in function scopes are +still named in lowerCamelCase. Note that lowerCamelCase is used +even if the variable holds a constructor.

6.2.9 Template parameter names

Template parameter names should be concise, single-word or single-letter identifiers, and must be all-caps, such as TYPE or THIS.

+

6.2.10 Module-local names

+ +

Module-local names that are not exported are implicitly private. They are not +marked @private and do not end in an underscore. This applies to classes, +functions, variables, constants, enums, and other module-local identifiers.

+

6.3 Camel case: defined

Sometimes there is more than one reasonable way to convert an English phrase @@ -1959,6 +2509,7 @@ ignore plain text formatting, so if you did this:

/**
  * Computes weight based on three factors:
+ *
  *  - items sent
  *  - items received
  *  - last timestamp
@@ -1971,7 +2522,7 @@ ignore plain text formatting, so if you did this:

?? for the complete list. Most tags must occupy their own line, with the tag at the beginning of the line.

-

Illegal:

+

Disallowed:

/**
  * The "param" tag must occupy its own line and may not be combined.
@@ -2029,7 +2580,7 @@ exports.method = function(foo) {
 };
 
-

Do not indent when wrapping a @fileoverview description.

+

Do not indent when wrapping a @desc or @fileoverview description.

7.5 Top/file-level comments

@@ -2088,8 +2639,9 @@ class Listable {

7.7 Enum and typedef comments

-

Enums and typedefs must be documented. Public enums and typedefs must have a -non-empty description. Individual enum items may be documented with a JSDoc +

All enums and typedefs must be documented with appropriate JSDoc tags +(@typedef or @enum) on the preceding line. Public enums and typedefs must +also have a description. Individual enum items may be documented with a JSDoc comment on the preceding line.

/**
@@ -2120,16 +2672,25 @@ For large record types, prefer @record.

7.8 Method and function comments

-

Parameter and return types must be documented. The this type should be -documented when necessary. Method, parameter, and return descriptions (but not -types) may be omitted if they are obvious from the rest of the method’s JSDoc or -from its signature. Method descriptions should start with a sentence written in -the third person declarative voice. If a method overrides a superclass method, -it must include an @override annotation. Overridden methods must include all -@param and @return annotations if any types are refined, but should omit -them if the types are all the same.

+

In methods and named functions, parameter and return types must be documented, +except in the case of same-signature @overrides, where all types are omitted. +The this type should be documented when necessary. Return type may be omitted +if the function has no non-empty return statements.

-
/** This is a class. */
+

Method, parameter, and return descriptions (but not types) may be omitted if +they are obvious from the rest of the method’s JSDoc or from its signature.

+ +

Method descriptions begin with a verb phrase that describes what the method +does. This phrase is not an imperative sentence, but instead is written in the +third person, as if there is an implied This method ... before it.

+ +

If a method overrides a superclass method, it must include an @override +annotation. Overridden methods inherit all JSDoc annotations from the super +class method (including visibility annotations) and they should be omitted in +the overridden method. However, if any type is refined in type annotations, all +@param and @return annotations must be specified explicitly.

+ +
/** A class that does something. */
 class SomeClass extends SomeBaseClass {
   /**
    * Operates on an instance of MyClass and returns something.
@@ -2154,38 +2715,63 @@ class SomeClass extends SomeBaseClass {
 function makeArray(arg) { ... }
 
+

If you only need to document the param and return types of a function, you may +optionally use inline JSDocs in the function's signature. These inline JSDocs +specify the return and param types without tags.

+ +
function /** string */ foo(/** number */ arg) {...}
+
+ +

If you need descriptions or tags, use a single JSDoc comment above the method. +For example, methods which return values need a @return tag.

+ +
class MyClass {
+  /**
+   * @param {number} arg
+   * @return {string}
+   */
+  bar(arg) {...}
+}
+
+ +
// Illegal inline JSDocs.
+
+class MyClass {
+  /** @return {string} */ foo() {...}
+}
+
+/** Function description. */ bar() {...}
+
-

Anonymous functions do not require JSDoc, though parameter types may be specified inline if the automatic type inference is insufficient.

+ +

In anonymous functions annotations are generally optional. If the automatic type +inference is insufficient or explicit annotation improves readability, then +annotate param and return types like this:

promise.then(
-    (/** !Array<number|string> */ items) => {
+    /** @return {string} */
+    (/** !Array<string> */ items) => {
       doSomethingWith(items);
-      return /** @type {string} */ (items[0]);
+      return items[0];
     });
 
+

For function type expressions, see ??.

+

7.9 Property comments

Property types must be documented. The description may be omitted for private properties, if name and type provide enough documentation for understanding the code.

-

Publicly exported constants are commented the same way as properties. Explicit -types may be omitted for @const properties initialized from an expression with -an obviously known type.

- -

Tip: A @const property’s type can be considered “obviously known” if it is -assigned directly from a constructor parameter with a declared type, or directly -from a function call with a declared return type. Non-const properties and -properties assigned from more complex expressions should have their types -declared explicitly.

+

Publicly exported constants are commented the same way as properties.

/** My class. */
 class MyClass {
   /** @param {string=} someString */
   constructor(someString = 'default string') {
-    /** @private @const */
+    /** @private @const {string} */
     this.someString_ = someString;
 
     /** @private @const {!OtherType} */
@@ -2201,7 +2787,7 @@ class MyClass {
 
 /**
  * The number of times we'll try before giving up.
- * @const
+ * @const {number}
  */
 MyClass.RETRY_COUNT = 33;
 
@@ -2215,20 +2801,55 @@ annotations attached to JSDoc tags must always be enclosed in braces.

7.10.1 Nullability

The type system defines modifiers ! and ? for non-null and nullable, -respectively. Primitive types (undefined, string, number, boolean, -symbol, and function(...): ...) and record literals ({foo: string, bar: -number}) are non-null by default. Do not add an explicit ! to these types. -Object types (Array, Element, MyClass, etc) are nullable by default, but -cannot be immediately distinguished from a name that is @typedef’d to a -non-null-by-default type. As such, all types except primitives and record -literals must be annotated explicitly with either ? or ! to indicate whether -they are nullable or not.

+respectively. These modifiers must precede the type.

+ +

Nullability modifiers have different requirements for different types, which +fall into two broad categories:

+ +
    +
  1. Type annotations for primitives (string, number, boolean, symbol, +undefined, null) and literals ({function(...): ...} and {{foo: +string...}}) are always non-nullable by default. Use the ? modifier to +make it nullable, but omit the redundant !.
  2. +
  3. Reference types (generally, anything in UpperCamelCase, including +some.namespace.ReferenceType) refer to a class, enum, record, or typedef +defined elsewhere. Since these types may or may not be nullable, it is +impossible to tell from the name alone whether it is nullable or not. Always +use explicit ? and ! modifiers for these types to prevent ambiguity at +use sites.
  4. +
+ +

Bad:

+ +
const /** MyObject */ myObject = null; // Non-primitive types must be annotated.
+const /** !number */ someNum = 5; // Primitives are non-nullable by default.
+const /** number? */ someNullableNum = null; // ? should precede the type.
+const /** !{foo: string, bar: number} */ record = ...; // Already non-nullable.
+const /** MyTypeDef */ def = ...; // Not sure if MyTypeDef is nullable.
+
+// Not sure if object (nullable), enum (non-nullable, unless otherwise
+// specified), or typedef (depends on definition).
+const /** SomeCamelCaseName */ n = ...;
+
+ +

Good:

+ +
const /** ?MyObject */ myObject = null;
+const /** number */ someNum = 5;
+const /** ?number */ someNullableNum = null;
+const /** {foo: string, bar: number} */ record = ...;
+const /** !MyTypeDef */ def = ...;
+const /** ?SomeCamelCaseName */ n = ...;
+

7.10.2 Type Casts

-

In cases where type checking doesn't accurately infer the type of an expression, -it is possible to tighten the type by adding a type annotation comment and -enclosing the expression in parentheses. Note that the parentheses are required.

+

In cases where the compiler doesn't accurately infer the type of an expression, +and the assertion functions in +goog.asserts +cannot remedy it , it is possible to +tighten the type by adding a type annotation comment and enclosing the +expression in parentheses. Note that the parentheses are required.

/** @type {number} */ (x)
 
@@ -2261,6 +2882,96 @@ const /** !Object<string, *> */ mapOfEverything = {};
  • Object is used for type hierarchy and not as map-like structure.
  • +

    7.10.4 Function type expressions

    + +

    Terminology Note: function type expression refers to a type annotation for +function types with the keyword function in the annotation (see examples +below).

    + +

    Where the function definition is given, do not use a function type expression. +Specify parameter and return types with @param and @return, or with inline +annotations (see ??). This includes +anonymous functions and functions defined and assigned to a const (where the +function jsdoc appears above the whole assignment expression).

    + +

    Function type expressions are needed, for example, inside @typedef, @param +or @return. Use it also for variables or properties of function type, if they +are not immediately initialized with the function definition.

    + +
      /** @private {function(string): string} */
    +  this.idGenerator_ = googFunctions.identity;
    +
    + +

    When using a function type expression, always specify the return type +explicitly. Otherwise the default return type is unknown (?), which leads to +strange and unexpected behavior, and is rarely what is actually desired.

    + +

    Bad - type error, but no warning given:

    + +
    /** @param {function()} generateNumber */
    +function foo(generateNumber) {
    +  const /** number */ x = generateNumber();  // No compile-time type error here.
    +}
    +
    +foo(() => 'clearly not a number');
    +
    + +

    Good:

    + +
    /**
    + * @param {function(): *} inputFunction1 Can return any type.
    + * @param {function(): undefined} inputFunction2 Definitely doesn't return
    + *      anything.
    + * NOTE: the return type of `foo` itself is safely implied to be {undefined}.
    + */
    +function foo(inputFunction1, inputFunction2) {...}
    +
    + +

    7.10.5 Whitespace

    + +

    Within a type annotation, a single space or line break is required after each +comma or colon. Additional line breaks may be inserted to improve readability or +avoid exceeding the column limit. These breaks should be chosen and indented +following the applicable guidelines (e.g. ?? and +??). No other whitespace is allowed in type +annotations.

    + +

    Good:

    + +
    /** @type {function(string): number} */
    +
    +/** @type {{foo: number, bar: number}} */
    +
    +/** @type {number|string} */
    +
    +/** @type {!Object<string, string>} */
    +
    +/** @type {function(this: Object<string, string>, number): string} */
    +
    +/**
    + * @type {function(
    + *     !SuperDuperReallyReallyLongTypedefThatForcesTheLineBreak,
    + *     !OtherVeryLongTypedef): string}
    + */
    +
    +/**
    + * @type {!SuperDuperReallyReallyLongTypedefThatForcesTheLineBreak|
    + *     !OtherVeryLongTypedef}
    + */
    +
    + +

    Bad:

    + +
    // Only put a space after the colon
    +/** @type {function(string) : number} */
    +
    +// Put spaces after colons and commas
    +/** @type {{foo:number,bar:number}} */
    +
    +// No space in union types
    +/** @type {number | string} */
    +
    +

    7.11 Visibility annotations

    Visibility annotations (@private, @package, @protected) may be specified @@ -2398,151 +3109,222 @@ System.

    In addition to the JSDoc described in Annotating JavaScript for the Closure Compiler the following tags are common and well supported by various -documentation generations tools (such as JsDossier) for purely documentation -purposes. - - - - - - - - - - -
    Tag - Template & Examples - Description -
    @author or @owner - @author username@google.com (First Last) -

    For example: -

    -/**
    +documentation generation tools (such as JsDossier) for purely documentation
    +purposes.

    + +

    You may also see other types of JSDoc annotations in third-party code. These +annotations appear in the JSDoc Toolkit Tag Reference but are not considered +part of valid Google style.

    + +
    + +
    9.1.2.1 @author or @owner - Not recommended.
    + +

    Not recommended.

    + +

    Syntax: @author username@google.com (First Last)

    + +
    /**
      * @fileoverview Utilities for handling textareas.
    - * @author kuth@google.com (Uthur Pendragon)
    + * @author kuth@google.com (Uthur Pendragon)
      */
    - 
    -
    Document the author of a file or the owner of a test, generally only - used in the @fileoverview comment. The @owner tag is used by the - unit test dashboard to determine who owns the test results. -

    Not recommended. -

    @bug - @bug bugnumber -

    For example: -

    -/** @bug 1234567 */
    +
    + +

    Documents the author of a file or the owner of a test, generally only used in +the @fileoverview comment. The @owner tag is used by the unit test dashboard +to determine who owns the test results.

    + + + +
    + +
    9.1.2.2 @bug
    + +

    Syntax: @bug bugnumber

    + +
    /** @bug 1234567 */
     function testSomething() {
       // …
     }
     
    -

    /** +/** * @bug 1234568 * @bug 1234569 */ function testTwoBugs() { // … } -

    -
    Indicates what bugs the given test function regression tests. -

    Multiple bugs should each have their own @bug line, to make - searching for regression tests as easy as possible. -

    @code - {@code ...} -

    For example: -

    -/**
    - * Moves to the next position in the selection.
    - * Throws {@code goog.iter.StopIteration} when it
    - * passes the end of the range.
    - * @return {!Node} The node at the next position.
    +
    + +

    Indicates what bugs the given test function regression tests.

    + +

    Multiple bugs should each have their own @bug line, to make searching for +regression tests as easy as possible.

    + + + +
    + +
    9.1.2.3 @code - Deprecated. Do not use.
    + +

    Deprecated. Do not use. Use Markdown backticks instead.

    + +

    Syntax: {@code ...}

    + +

    Historically, `BatchItem` was written as +{@code BatchItem}.

    + +
    /** Processes pending `BatchItem` instances. */
    +function processBatchItems() {}
    +
    + +

    Indicates that a term in a JSDoc description is code so it may be correctly +formatted in generated documentation.

    + +
    + +
    + +
    9.1.2.4 @desc
    + +

    Syntax: @desc Message description

    + +
    /** @desc Notifying a user that their account has been created. */
    +exports.MSG_ACCOUNT_CREATED = goog.getMsg(
    +    'Your account has been successfully created.');
    +
    + +
    + +
    + +
    9.1.2.5 @link
    + +

    Syntax: {@link ...}

    + +

    This tag is used to generate cross-reference links within generated +documentation.

    + +
    /** Processes pending {@link BatchItem} instances. */
    +function processBatchItems() {}
    +
    + +

    Historical note: @link tags have also been used to create external links in +generated documentation. For external links, always use Markdown's link syntax +instead:

    + +
    /**
    + * This class implements a useful subset of the
    + * [native Event interface](https://dom.spec.whatwg.org/#event).
      */
    -goog.dom.RangeIterator.prototype.next = function() {
    -  // …
    -};
    -
    -
    Indicates that a term in a JSDoc description is code so it may be - correctly formatted in generated documentation. -
    @see - @see Link -

    For example: -

    -/**
    +class ApplicationEvent {}
    +
    + + + +
    + +
    9.1.2.6 @see
    + +

    Syntax: @see Link

    + +
    /**
      * Adds a single item, recklessly.
      * @see #addSafely
      * @see goog.Collect
      * @see goog.RecklessAdder#add
      */
    - 
    -
    Reference a lookup to another class function or method. -
    @supported - @supported Description -

    For example: -

    -/**
    +
    + +

    Reference a lookup to another class function or method.

    + + + +
    + +
    9.1.2.7 @supported
    + +

    Syntax: @supported Description

    + +
    /**
      * @fileoverview Event Manager
    - * Provides an abstracted interface to the
    - * browsers' event systems.
    + * Provides an abstracted interface to the browsers' event systems.
      * @supported IE10+, Chrome, Safari
      */
    -
    -
    Used in a fileoverview to indicate what browsers are supported by - the file. -
    @desc - @desc Message description -

    For example: -

    -/** @desc Notifying a user that their account has been created. */
    -exports.MSG_ACCOUNT_CREATED = goog.getMsg(
    -    'Your account has been successfully created.');
    - 
    -

    +
    -

    You may also see other types of JSDoc annotations in third-party code. These -annotations appear in the JSDoc Toolkit Tag Reference but are not considered -part of valid Google style.

    +

    Used in a fileoverview to indicate what browsers are supported by the file.

    + +

    9.1.3 Framework specific annotations

    -

    The following annotations are specific to a particular framework. - - - - - - -
    Framework - Tag - Documentation -
    Angular 1 - @ngInject -
    Polymer - @polymerBehavior - - - https://github.com/google/closure-compiler/wiki/Polymer-Pass - -

    +

    The following annotations are specific to a particular framework.

    + +
    + +
    9.1.3.1 @ngInject for Angular 1
    + +
    + +
    + +
    9.1.3.2 @polymerBehavior for Polymer
    + + + +

    https://github.com/google/closure-compiler/wiki/Polymer-Pass +

    + +
    + +
    + +

    9.1.4 Notes about standard Closure Compiler annotations

    -

    The following tags used to be standard but are now deprecated. - - - - - - -
    Tag - Template & Examples - Description -
    @expose - @expose - Deprecated. Do not use. Use @export and/or @nocollapse - instead. -
    @inheritDoc - @inheritDoc - Deprecated. Do not use. Use @override instead. -

    +

    The following tags used to be standard but are now deprecated.

    + +
    + +
    9.1.4.1 @expose - Deprecated. Do not use.
    + +

    Deprecated. Do not use. Use @export and/or @nocollapse instead.

    + +
    + +
    + +
    9.1.4.2 @inheritDoc - Deprecated. Do not use.
    + +

    Deprecated. Do not use. Use @override instead.

    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +

    9.2 Commonly misunderstood style rules

    @@ -2553,14 +3335,13 @@ list of myths.)

    • Neither a copyright statement nor @author credit is required in a source file. (Neither is explicitly recommended, either.)
    • -
    • Aside from the constructor coming first -(??), there is no hard and fast rule -governing how to order the members of a class (??).
    • +
    • There is no hard and fast rule governing how to order the members of a +class (??).
    • Empty blocks can usually be represented concisely as {}, as detailed in (??).
    • The prime directive of line-wrapping is: prefer to break at a higher syntactic level (??).
    • -
    • Non-ASCII characters are allowed in string literals, comments and Javadoc, +
    • Non-ASCII characters are allowed in string literals, comments and JSDoc, and in fact are recommended when they make the code easier to read than the equivalent Unicode escape would (??).
    @@ -2579,7 +3360,9 @@ code lowering).

    This program reformats JavaScript source code into Google Style, and also follows a number of -non-required but frequently readability-enhancing formatting practices.

    +non-required but frequently readability-enhancing formatting practices. +The output produced by clang-format is compliant with the style guide. +

    clang-format is not required. Authors are allowed to change its output, and reviewers are allowed to ask for such changes; disputes are worked out in the @@ -2689,12 +3472,13 @@ expression to define a function within a block:

    9.4.4 Dependency management with goog.provide/goog.require

    -

    goog.provide is deprecated. All new files should use goog.module, even in -projects with existing goog.provide usage. The following rules are for -pre-existing goog.provide files, only.

    -
    9.4.4.1 Summary
    +

    WARNING: goog.provide dependency management is deprecated. All new files, +even in projects using goog.provide for older files, should use +goog.module. The following rules are for +pre-existing goog.provide files only.

    +
    • Place all goog.provides first, goog.requires second. Separate provides from requires with an empty line.
    • @@ -2704,11 +3488,6 @@ if necessary.
    • Only provide top-level symbols.
    -

    As of Oct 2016, goog.provide/goog.require dependency management is -deprecated. All new files, even in projects using goog.provide for older -files, should use -goog.module.

    -

    goog.provide statements should be grouped together and placed first. All goog.require statements should follow. The two lists should be separated with an empty line.

    @@ -2758,8 +3537,8 @@ goog.provide('foo.bar.method');
    9.4.4.2 Aliasing with goog.scope
    -

    goog.scope is deprecated. New files should not use goog.scope even in -projects with existing goog.scope usage.

    +

    WARNING: goog.scope is deprecated. New files should not use goog.scope +even in projects with existing goog.scope usage.

    goog.scope may be used to shorten references to namespaced symbols in code using goog.provide/goog.require dependency management.

    @@ -2811,6 +3590,22 @@ SomeType.prototype.findButton = function() { }); // goog.scope
    +
    9.4.4.3 goog.forwardDeclare
    + +

    Prefer to use goog.requireType instead of goog.forwardDeclare to break +circular dependencies between files in the same library. Unlike goog.require, +a goog.requireType statement is allowed to import a namespace before it is +defined.

    + +

    goog.forwardDeclare may still be used in legacy code to break circular +references spanning across library boundaries, but newer code should be +structured to avoid it.

    + +

    goog.forwardDeclare statements must follow the same style rules as +goog.require and goog.requireType. The entire block of +goog.forwardDeclare, goog.require and goog.requireType statements is +sorted alphabetically.

    +