google-javascript-style
Use when maintaining existing JavaScript under Google's source formatting, naming, module, language-feature, JSDoc, and policy conventions. The upstream guide is no longer updated. For TypeScript, use
SKILL.mdskills/google-javascript-style/SKILL.md
GitHubGoogle JavaScript Style Guide
Apply this guidance to the actual project. Repository requirements and newer authoritative guidance take precedence.
2.1 File name
File names must be all lowercase and may include underscores (_) or dashes
(-), but no additional punctuation. Follow the convention that your project
uses. Filenames’ extension must be .js.
3 Source file structure
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:
- License or copyright information, if present
@fileoverviewJSDoc, if presentgoog.modulestatement, if agoog.modulefile- ES
importstatements, if an ES module goog.requireandgoog.requireTypestatements- The file’s implementation Exactly one blank line separates each section that is present, except the file's implementation, which may be preceded by 1 or 2 blank lines.
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.
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.
3.4.2.2 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.
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.
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.
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.
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 require calls that are standalone (generally these are for modules
imported just for their side effects).
4.1.1 Braces are used for all control structures
Braces are required for all control structures (i.e. if, else, for, do,
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.
Exception: A simple if statement that can fit entirely on a single line with
no wrapping (and that doesn’t have an else) may be kept on a single line with no
braces when it improves readability. This is the only case in which a control
structure may omit braces and newlines.
4.2 Block indentation: +2 spaces
Each time a new block or block-like construct is opened, the indent increases by two spaces. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block.
4.3.2 Semicolons are required
Every statement must be terminated with a semicolon. Relying on automatic semicolon insertion is forbidden.
4.4 Column limit: 80
JavaScript code has a column limit of 80 characters. Except as noted below, any line that would exceed this limit must be line-wrapped.
goog.module,goog.requireandgoog.requireTypestatements.- ES module
importandexport fromstatements. - 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.1 Where to break
The prime directive of line-wrapping is: prefer to break at a higher syntactic level.
- When a line is broken at an operator the break comes after the symbol. (Note
that this is not the same practice used in Google style for Java.)
- This does not apply to the "dot" (
.), which is not actually an operator.
- This does not apply to the "dot" (
- A method or constructor name stays attached to the open parenthesis (
() that follows it. - A comma (
,) stays attached to the token that precedes it. - A line break is never added between a return and the return value as this would change the meaning of the code.
- JSDoc annotations with type names break after "{". This is necessary as
annotations with optional types (@const, @private, @param, etc) do not scan
the next line.
Note: The primary goal for line wrapping is to have clear code, not necessarily code that fits in the smallest number of lines.
4.5.2 Indent continuation lines at least +4 spaces
When line-wrapping, each line after the first (each continuation line) is indented at least +4 from the original line, unless it falls under the rules of block indentation. When there are multiple continuation lines, indentation may be varied beyond +4 as appropriate. In general, continuation lines at a deeper syntactic level are indented by larger multiples of 4, and two lines use the same indentation level if and only if they begin with syntactically parallel elements.
5.1.1 Use const and let
Declare all local variables with either const or let. Use const by
default, unless a variable needs to be reassigned. The var keyword
must not be used.
5.1.2 One variable per declaration
Every local variable declaration declares only one variable: declarations such
as let a = 1, b = 2; are not used.
5.1.3 Declared when needed, initialized as soon as possible
Local variables are not habitually declared at the start of their containing block or block-like construct. Instead, local variables are declared close to the point they are first used (within reason), to minimize their scope, and initialized as soon as possible.
5.2.1 Use trailing commas
Include a trailing comma whenever there is a line break between the final element and the closing bracket.
5.3.3 Do not mix quoted and unquoted keys
Object literals may represent either structs (with unquoted keys and/or
symbols) or dicts (with quoted and/or computed keys). Do not mix these key
types in a single object literal.
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.
5.4.2 Fields
Define 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). Annotate non-public fields with
the proper visibility annotation (@private, @protected, @package).
@private fields' names may optionally end with an underscore. Fields must not
be defined within a nested scope in the constructor nor on a concrete class's
prototype.
5.4.6 Do not manipulate prototypes directly
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 classes.
Mixins and modifying the
prototypes of builtin objects are explicitly forbidden.
5.4.11 Do not create static container classes
Do not use container classes with only static methods or properties for the sake of namespacing.
5.4.12 Do not define nested namespaces
Do not define a nested type (e.g. class, typedef, enum, interface) on another module-local name.
5.5.3 Arrow functions
Arrow functions provide a concise function syntax and simplify scoping this
for nested functions. Prefer arrow functions over the function keyword for
nested functions.
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 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).
5.5.5.2 Rest parameters
Use a rest parameter instead of accessing arguments. Rest parameters are
typed with a ... prefix in their JSDoc. The rest parameter must be the last
parameter in the list. There is no space between the ... and the parameter
name. Do not name the rest parameter var_args. Never name a local variable or
parameter arguments, which confusingly shadows the built-in name.
5.6.1 Use single quotes
Ordinary string literals are delimited with single quotes ('), rather than
double quotes (").
Ordinary string literals may not span multiple lines.
5.6.3 No line continuations
Do not use line continuations (that is, ending a line inside a string literal 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.
5.8.1 For loops
With ES6, the language now has three different kinds of for loops. All may be
used, though for-of loops should be preferred when possible.
for-in loops may only be used on dict-style objects, and should not be used to iterate over an
array. Object.prototype.hasOwnProperty should be used in for-in loops to
exclude unwanted prototype properties. Prefer for-of and Object.keys over
for-in when possible.
5.8.2 Exceptions
Exceptions are an important part of the language and should be used whenever
exceptional cases occur. Always throw Errors or subclasses of Error: never
throw string literals or other objects. Always use new when constructing an
Error.
This treatment extends to Promise rejection values as Promise.reject(obj) is
equivalent to throw obj; in async functions.
5.8.2.1 Empty catch blocks
It is very rarely correct to do nothing in response to a caught exception. When it truly is appropriate to take no action whatsoever in a catch block, the reason this is justified is explained in a comment.
5.8.3.1 Fall-through: commented
Within a switch block, each statement group either terminates abruptly (with a
break, return or thrown exception), or is marked with a comment to
indicate that execution will or might continue into the next statement group.
Any comment that communicates the idea of fall-through is sufficient (typically
// fall through). This special comment is not required in the last 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. The default statement group must be last.
5.10 Equality Checks
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.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.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
(e.g., the current TC39 working draft, proposals at any stage, or proposed but
not-yet-complete web standards), or proprietary features that are only
implemented in some browsers. Use only features defined in the current ECMA-262
or WHATWG standards. (Note that projects writing against specific APIs, such as
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.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.
The wrappers may be called as functions for coercing (which is preferred over
using + or concatenating the empty string) or creating symbols.
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 JSCompiler’s runtime library will provide standards-compliant polyfills where 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).
6.1 Rules common to all identifiers
Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, underscores and very rarely (when required by frameworks like Angular) dollar signs. Give as descriptive a name as possible, within reason. Do not worry about saving horizontal space as it is far more important to make your code immediately 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. Exception: Variables that are in scope for 10 lines or fewer, including arguments that are not part of an exported API, may use short (e.g. single letter) variable names.
6.2.2 Class names
Class, interface, record, and typedef names are written in UpperCamelCase.
Unexported classes are simply locals: they are not marked @private.
6.2.3 Method names
Method names are written in lowerCamelCase. Names for @private methods may
optionally end with a trailing underscore.
6.2.5 Constant names
Constant names use CONSTANT_CASE: all uppercase letters, with words separated
by underscores. There is no reason for a constant to be named with a trailing
underscore, since private static properties can be replaced by (implicitly
private) module locals.
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 is used
even if the variable holds a constructor.
7.8 Method and function comments
In methods and named functions, parameter and return types must be documented,
even in the case of same-signature @overrides. The this type should be
documented when necessary. Return type may be omitted if the function has no
non-empty return statements.
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.
7.10.1 Nullability
The type system defines modifiers ! and ? for non-null and nullable,
respectively. These modifiers must precede the type.
- 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, includingsome.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.
7.11 Visibility annotations
Visibility annotations (@private, @package, @protected) may be specified
in a @fileoverview block, or on any exported symbol or property. Do not
specify visibility for local variables, whether within a function or at the top
level of a module. @private names may optionally end with an underscore.
8.2.2 How to handle a warning
Before doing anything, make sure you understand exactly what the warning is telling you. If you're not positive why a warning is appearing, ask for help . Once you understand the warning, attempt the following solutions in order:
- First, fix it or work around it. Make a strong attempt to actually address the warning, or find another way to accomplish the task that avoids the situation entirely.
- Otherwise, determine if it's a false alarm. If you are convinced that
the warning is invalid and that the code is actually safe and correct, add a
comment to convince the reader of this fact and apply the
@suppressannotation. - Otherwise, leave a TODO comment. This is a last resort. If you do this, do not suppress the warning. The warning should be visible until it can be taken care of properly.
8.2.3 Suppress a warning at the narrowest reasonable scope
Warnings are suppressed at the narrowest reasonable scope, usually that of a single local variable or very small method. Often a variable or method is extracted for that reason alone. Even a large number of suppressions in a class is still better than blinding the entire class to this type of warning.
8.4.1 Reformatting existing code
- It is not required to change all existing code to meet current style guidelines. Reformatting existing code is a trade-off between code churn and consistency. Style rules evolve over time and these kinds of tweaks to maintain compliance would create unnecessary churn. However, if significant changes are being made to a file it is expected that the file will be in Google Style.
- Be careful not to allow opportunistic style fixes to muddle the focus of a CL. If you find yourself making a lot of style changes that aren’t critical to the central focus of a CL, promote those changes to a separate CL.
8.4.2 Newly added code: use Google Style
Brand new files use Google Style, regardless of the style choices of other files in the same package. If this reformatting is not done, then new code should be as consistent as possible with existing code in the same file, but must not violate the style guide.