-
Notifications
You must be signed in to change notification settings - Fork 0
Style Guide
Braces are required for all control structures (i.e. if, else, for, do, while, as well as any others), unless the body contains only a single statement. The first statement of a non-empty block must begin on its own line.
Disallowed:
if (someVeryLongCondition()) { doSomething();
doSomethingElse();
}
for (let i = 0; i < foo.length; i++) bar(foo[i]);Exception: A simple if statement that can fit entirely on a single line with no wrapping may be kept on a single line with no braces when it improves readability.
if (shortCondition()) foo();Braces follow the Kernighan and Ritchie style ("Egyptian brackets") for nonempty blocks and block-like
- No line break before the opening brace.
- Line break after the opening brace.
- Line break before the closing brace.
- Line break after the closing brace if that brace terminates a statement or the body of a function or class statement, or a class method.
Specifically, there is no line break after the brace if it is followed by else, catch, while, or a comma, semicolon, or right-parenthesis.
Example:
class InnerClass {
constructor() {}
/** @param {number} foo */
method(foo) {
if (condition(foo)) {
try {
// Note: this might fail.
something();
} catch (err) {
recover();
}
}
}
}An empty block or block-like construct may be closed immediately after it is opened, with no characters, space, or line break in between (i.e. {}), unless it is a part of a multi-block statement (one that directly contains multiple blocks: if/else or try/catch/finally).
Example:
const doNothing = () => {};Disallowed:
if (condition) {
// …
} else if (otherCondition) {} else {
// …
}
try {
// …
} catch (e) {}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.
Any array literal may optionally be formatted as if it were a “block-like construct.” For example, the following are all valid (not an exhaustive list):
const a = [
0,
1,
2,
];
const b =
[0, 1, 2];const c = [0, 1, 2];
someMethod(foo, [
0, 1, 2,
], bar);Other combinations are allowed, particularly when emphasizing semantic groupings between elements, but should not be used only to reduce the vertical size of larger arrays.
Any object literal may optionally be formatted as if it were a “block-like construct.”
const a = {
a: 0,
b: 1,
};
const b =
{a: 0, b: 1};const c = {a: 0, b: 1};
someMethod(foo, {
a: 0, b: 1,
}, bar);Class literals (whether declarations or expressions) are indented as blocks. Do not add semicolons after methods, or after the closing brace of a class declaration (statements—such as assignments—that contain class expressions are still terminated with a semicolon). Use the extends keyword, but not the @extends JSDoc annotation unless the class extends a templatized type.
Example:
class Foo {
constructor() {
/** @type {number} */
this.x = 42;
}
/** @return {number} */
method() {
return this.x;
}
}
Foo.Empty = class {};/** @extends {Foo<string>} */
foo.Bar = class extends Foo {
/** @override */
method() {
return super.method() / 2;
}
};
/** @interface */
class Frobnicator {
/** @param {string} message */
frobnicate(message) {}
}When declaring an anonymous function in the list of arguments for a function call, the body of the function is indented two spaces more than the preceding indentation depth.
Example:
prefix.something.reallyLongFunctionName('whatever', (a1, a2) => {
// Indent the function body +2 relative to indentation depth
// of the 'prefix' statement one line above.
if (a1.equals(a2)) {
someOtherLongFunctionName(a1);
} else {
andNowForSomethingCompletelyDifferent(a2.parrot);
}
});As with any other block, the contents of a switch block are indented +2.
After a switch label, a newline appears, and the indentation level is increased +2, exactly as if a block were being opened. An explicit block may be used if required by lexical scoping. The following switch label returns to the previous indentation level, as if a block had been closed.
A blank line is required between a break and the following case.
Example:
switch (animal) {
case Animal.BANDERSNATCH:
handleBandersnatch();
break;
case Animal.JABBERWOCK:
handleJabberwock();
break;
default:
throw new Error('Unknown animal');
}Every statement must be terminated with a semicolon. Relying on automatic semicolon insertion is forbidden.
JavaScript code has a column limit of 80 characters. Except lines where obeying the column limit is not possible or would hinder discoverability.
The prime directive of line-wrapping is: prefer to break at a higher syntactic level.
Preferred:
currentEstimate =
calc(currentEstimate + x * currentEstimate) /
2.0;Discouraged:
currentEstimate = calc(currentEstimate + x *
currentEstimate) / 2.0;In the preceding example, the syntactic levels from highest to lowest are as follows: assignment, division, function call, parameters, number constant.
Operators are wrapped as follows:
- When a line is broken at an operator the break comes after the symbol. (Note that this does not apply to the "dot" (.), which is not actually an operator.)
- A method or constructor name stays attached to the open parenthesis (() that follows it.
- A comma (,) stays attached to the token that precedes it.
All comments must have a space between the commented text and the comment operator.
Example:
// this is allowed
/*
* This is
* also allowed
*/Disallowed:
//Don't do this
/*
*This is
*not okay
*/A space must be inserted between a control structure term and its following parenthesis
Example:
if (0 === true)Disallowed:
if(0 === true)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.
Every local variable declaration declares only one variable: declarations such as let a = 1, b = 2; are not used.
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.
All functions, must be declared as arrow functions. The keyword function is strictly forbidden.
Example:
const myFunc = (foo) => {
const bar = 4;
return foo + bar;
};
const myOtherFunc = (x, y) => x + y; Disallowed:
function myFunc(foo) {
return foo + 'bar';
}Use template literals (delimited with `) over complex string concatenation, particularly if multiple string literals are involved. Template literals may span multiple lines.
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.
Example:
function arithmetic(a, b) {
return `Here is a table of arithmetic operations:
${a} + ${b} = ${a + b}
${a} - ${b} = ${a - b}
${a} * ${b} = ${a * b}
${a} / ${b} = ${a / b}`;
}When possible use map or for (const n of arr) over while loops and traditional for loops (for (let i = 0; i < x; ++i))