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.
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:
@fileoverview
JSDoc, if presentgoog.module
statementgoog.require
statementsgoog.module
statement, if a goog.module
fileimport
statements, if an ES modulegoog.require
and goog.requireType
statementsgoog.module
statementAll 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 require
d 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.require
d, goog.module.get
d, 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:
-- 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).
-goog.module
and goog.require
statements (see ?? and
-??).
+goog.module
, goog.require
and goog.requireType
statements (see
+?? and ??).
+- ES module
import
and export from
statements (see
+?? and ??).
+- 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.
-- Separating any reserved word (such as
if
, for
, or catch
) from an open
-parenthesis ((
) that follows it on that line.
+- 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.
- Separating any reserved word (such as
else
or catch
) from a closing
curly brace (}
) that precedes it on that line.
- Before any open curly brace (
{
), with two exceptions:
- 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}]})
).
-- In a template expansion, as it is forbidden by the language
-(e.g.
abc${1 + 2}def
).
+- In a template expansion, as it is forbidden by the language (e.g. valid:
+
`ab${1 + 2}cd`
, invalid: `xy$ {3}z`
).
- On both sides of any binary or ternary operator.
- After a comma (
,
) or semicolon (;
). Note that spaces are never allowed
before these characters.
- After the colon (
:
) in an object literal.
-- On both sides of the double slash (
//
) that begins an end-of-line
-comment. Here, multiple spaces are allowed, but not required.
-- 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) {
).
+- On both sides of the double slash (
//
) that begins an end-of-line comment.
+Here, multiple spaces are allowed, but not required.
+- 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 prototype
s, 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 @override
s,
-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.
function variadic(array, ...numbers) {}
-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 @override
s 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 Error
s 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.require
s
@@ -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 @override
s, 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:
+
+
+- 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 !
.
+- 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.
+
+
+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.provide
s first, goog.require
s 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.
+