-
Notifications
You must be signed in to change notification settings - Fork 1
Eslint rules
Note: We used Airbnb JavaScript Style Guide for the most of rules, examples and explanations.
- References
- Objects
- Arrays
- Strings
- Functions
- Arrow Functions
- Classes & Constructors
- Modules
- Iterators and Generators
- Properties
- Variables
- Comparison Operators & Equality
- Blocks
- Comments
- Whitespace
- Commas
- Semicolons
- Naming Conventions
-
1.1 Use
const
for all of your references; avoid usingvar
. eslint:prefer-const
,no-const-assign
Why? This ensures that you can’t reassign your references, which can lead to bugs and difficult to comprehend code.
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
1.2 If you must reassign references, use
let
instead ofvar
. eslint:no-var
Why?
let
is block-scoped rather than function-scoped likevar
.// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
-
2.1 Use the literal syntax for object creation. eslint:
no-new-object
// bad const item = new Object(); // good const item = {};
-
3.1 Use the literal syntax for array creation. eslint:
no-array-constructor
// bad const items = new Array(); // good const items = [];
-
3.2 Use return statements in array method callbacks. It’s ok to omit the return if the function body consists of a single statement returning an expression without side effects, following 7.2. eslint:
array-callback-return
// good [1, 2, 3].map((x) => { const y = x + 1; return x * y; }); // good [1, 2, 3].map(x => x + 1); // bad - no returned value means `acc` becomes undefined after the first iteration [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; }); // good [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; return flatten; }); // bad inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } else { return false; } }); // good inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } return false; });
-
4.1 Use single quotes
''
for strings. eslint:quotes
// bad const name = "Capt. Janeway"; // bad - template literals should contain interpolation or newlines const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
-
4.2 When programmatically building up strings, use template strings instead of concatenation. eslint:
prefer-template
Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // good function sayHi(name) { return `How are you, ${ name }?`; } // good function sayHi(name) { return `How are you, ${name}?`; }
-
4.4 Do not unnecessarily escape characters in strings. eslint:
no-useless-escape
Why? Backslashes harm readability, thus they should only be present when necessary.
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; const foo = `my name is '${name}'`;
-
5.1 Wrap immediately invoked function expressions in parentheses. eslint:
wrap-iife
Why? An immediately invoked function expression is a single unit - wrapping both it, and its invocation parens, in parens, cleanly expresses this. Note that in a world with modules everywhere, you almost never need an IIFE.
// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
-
5.2 Never declare a function in a non-function block (
if
,while
, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. eslint:no-loop-func
-
5.3 Note: ECMA-262 defines a
block
as a list of statements. A function declaration is not a statement.// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
-
5.4 Never use the Function constructor to create a new function. eslint:
no-new-func
Why? Creating a function in this way evaluates a string similarly to
eval()
, which opens vulnerabilities.// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
-
5.5 Spacing in a function signature. eslint:
space-before-blocks
Why? Consistency is good, and you shouldn’t have to add or remove a space when adding or removing a name.
// bad const f = function(){}; const f = function (){}; // good const f = function() {}; const f = function () {};
-
5.6 Never mutate parameters. eslint:
no-param-reassign
Why? Manipulating objects passed in as parameters can cause unwanted variable side effects in the original caller.
// bad function f1(obj) { obj.key = 1; } // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; }
-
5.7 Never reassign parameters. eslint:
no-param-reassign
Why? Reassigning parameters can lead to unexpected behavior, especially when accessing the
arguments
object. It can also cause optimization issues, especially in V8.// bad function f1(a) { a = 1; // ... } function f2(a) { if (!a) { a = 1; } // ... } // good function f3(a) { const b = a || 1; // ... } function f4(a = 1) { // ... }
-
6.1 When you must use an anonymous function (as when passing an inline callback), use arrow function notation. eslint:
prefer-arrow-callback
,arrow-spacing
Why? It creates a version of the function that executes in the context of
this
, which is usually what you want, and is a more concise syntax.Why not? If you have a fairly complicated function, you might move that logic out into its own named function expression.
// bad [1, 2, 3].map(function (x) { const y = x + 1; return x * y; }); // good [1, 2, 3].map((x) => { const y = x + 1; return x * y; });
-
6.2 If the function body consists of a single statement returning an expression without side effects, omit the braces and use the implicit return. Otherwise, keep the braces and use a
return
statement. eslint:arrow-parens
,arrow-body-style
Why? Syntactic sugar. It reads well when multiple functions are chained together.
// bad [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map(number => `A string containing the ${number}.`); // good [1, 2, 3].map((number) => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map((number, index) => ({ [index]: number, })); // No implicit return with side effects function foo(callback) { const val = callback(); if (val === true) { // Do something if callback returns true } } let bool = false; // bad foo(() => bool = true); // good foo(() => { bool = true; });
-
6.3 If your function takes a single argument and doesn’t use braces, omit the parentheses. Otherwise, always include parentheses around arguments for clarity and consistency. Note: it is also acceptable to always use parentheses, in which case use the “always” option for eslint. eslint:
arrow-parens
Why? Less visual clutter.
// bad [1, 2, 3].map((x) => x * x); // good [1, 2, 3].map(x => x * x); // good [1, 2, 3].map(number => ( `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` )); // bad [1, 2, 3].map(x => { const y = x + 1; return x * y; }); // good [1, 2, 3].map((x) => { const y = x + 1; return x * y; });
-
6.4 Avoid confusing arrow function syntax (
=>
) with comparison operators (<=
,>=
). eslint:no-confusing-arrow
// bad const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize; // bad const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize; // good const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize); // good const itemHeight = (item) => { const { height, largeSize, smallSize } = item; return height > 256 ? largeSize : smallSize; };
-
6.5 Enforce the location of arrow function bodies with implicit returns. eslint:
implicit-arrow-linebreak
// bad (foo) => bar; (foo) => (bar); // good (foo) => bar; (foo) => (bar); (foo) => ( bar )
-
7.1 Avoid duplicate class members. eslint:
no-dupe-class-members
Why? Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug.
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }
-
8.1 Only import from a path in one place. eslint:
no-duplicate-imports
Why? Having multiple lines that import from the same path can make code harder to maintain.
// bad import foo from 'foo'; // … some other imports … // import { named1, named2 } from 'foo'; // good import foo, { named1, named2 } from 'foo'; // good import foo, { named1, named2, } from 'foo';
-
9.1 Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like
for-in
orfor-of
. eslint:no-iterator
no-restricted-syntax
Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.
Use
map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ ... to iterate over arrays, andObject.keys()
/Object.values()
/Object.entries()
to produce arrays so you can iterate over objects.const numbers = [1, 2, 3, 4, 5]; // bad let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // good let sum = 0; numbers.forEach((num) => { sum += num; }); sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; // bad const increasedByOne = []; for (let i = 0; i < numbers.length; i++) { increasedByOne.push(numbers[i] + 1); } // good const increasedByOne = []; numbers.forEach((num) => { increasedByOne.push(num + 1); }); // best (keeping it functional) const increasedByOne = numbers.map(num => num + 1);
-
10.1 Use dot notation when accessing properties. eslint:
dot-notation
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
-
11.1 Always use
const
orlet
to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint:no-undef
prefer-const
// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
-
11.2 Use one
const
orlet
declaration per variable. eslint:one-var
Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a
;
for a,
or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once.// bad const items = getItems(), goSportsTeam = true, dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) const items = getItems(), goSportsTeam = true; dragonball = 'z'; // good const items = getItems(); const goSportsTeam = true; const dragonball = 'z';
-
11.3 Don’t chain variable assignments. eslint:
no-multi-assign
Why? Chaining variable assignments creates implicit global variables.
// bad (function example() { // JavaScript interprets this as // let a = ( b = ( c = 1 ) ); // The let keyword only applies to variable a; variables b and c become // global variables. let a = b = c = 1; }()); console.log(a); // throws ReferenceError console.log(b); // 1 console.log(c); // 1 // good (function example() { let a = 1; let b = a; let c = a; }()); console.log(a); // throws ReferenceError console.log(b); // throws ReferenceError console.log(c); // throws ReferenceError // the same applies for `const`
-
11.4 Avoid linebreaks before or after
=
in an assignment. If your assignment violatesmax-len
, surround the value in parens. eslintoperator-linebreak
.Why? Linebreaks surrounding
=
can obfuscate the value of an assignment.// bad const foo = superLongLongLongLongLongLongLongLongFunctionName(); // bad const foo = 'superLongLongLongLongLongLongLongLongString'; // good const foo = ( superLongLongLongLongLongLongLongLongFunctionName() ); // good const foo = 'superLongLongLongLongLongLongLongLongString';
-
11.5 Disallow unused variables. eslint:
no-unused-vars
Why? Variables that are declared and not used anywhere in the code are most likely an error due to incomplete refactoring. Such variables take up space in the code and can lead to confusion by readers.
// bad var some_unused_var = 42; // Write-only variables are not considered as used. var y = 10; y = 5; // A read for a modification of itself is not considered as used. var z = 0; z = z + 1; // Unused function arguments. function getX(x, y) { return x; } // good function getXPlusY(x, y) { return x + y; } var x = 1; var y = a + 2; alert(getXPlusY(x, y)); // 'type' is ignored even if unused because it has a rest property sibling. // This is a form of extracting an object that omits the specified keys. var { type, ...coords } = data; // 'coords' is now the 'data' object without its 'type' property.
-
12.1 Ternaries should not be nested and generally be single line expressions. eslint:
no-nested-ternary
// bad const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null; // split into 2 separated ternary expressions const maybeNull = value1 > value2 ? 'baz' : null; // better const foo = maybe1 > maybe2 ? 'bar' : maybeNull; // best const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
-
12.2 When mixing operators, enclose them in parentheses. The only exception is the standard arithmetic operators (
+
,-
,*
, &/
) since their precedence is broadly understood. eslint:no-mixed-operators
Why? This improves readability and clarifies the developer’s intention.
// bad const foo = a && b < 0 || c > 0 || d + 1 === 0; // bad const bar = a ** b - 5 % d; // bad // one may be confused into thinking (a || b) && c if (a || b && c) { return d; } // good const foo = (a && b < 0) || c > 0 || (d + 1 === 0); // good const bar = (a ** b) - (5 % d); // good if (a || (b && c)) { return d; } // good const bar = a + b / c * d;
-
13.1 Use braces with all multi-line blocks. eslint:
nonblock-statement-body-position
// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function foo() { return false; } // good function bar() { return false; }
-
13.2 If you're using multi-line blocks with
if
andelse
, putelse
on the same line as yourif
block’s closing brace. eslint:brace-style
// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
-
13.3 If an
if
block always executes areturn
statement, the subsequentelse
block is unnecessary. Areturn
in anelse if
block following anif
block that contains areturn
can be separated into multipleif
blocks. eslint:no-else-return
// bad function foo() { if (x) { return x; } else { return y; } } // bad function cats() { if (x) { return x; } else if (y) { return y; } } // bad function dogs() { if (x) { return x; } else { if (y) { return y; } } } // good function foo() { if (x) { return x; } return y; } // good function cats() { if (x) { return x; } if (y) { return y; } } // good function dogs(x) { if (x) { if (z) { return y; } } else { return z; } }
-
14.1 Use
/** ... */
for multi-line comments. eslint:multiline-comment-style
// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
-
14.2 Use
//
for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block. eslint:multiline-comment-style
// bad const active = true; // is current tab // good // is current tab const active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this.type || 'no type'; return type; } // good function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this.type || 'no type'; return type; } // also good function getType() { // set the default type to 'no type' const type = this.type || 'no type'; return type; }
-
14.3 Start all comments with a space to make it easier to read. eslint:
spaced-comment
// bad //is current tab const active = true; // good // is current tab const active = true; // bad /** *make() returns a new element *based on the passed-in tag name */ function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
-
15.1 Use soft tabs (space character) set to 4 spaces. eslint:
indent
// bad function foo() { ∙∙let name; } // bad function bar() { ∙let name; } // good function baz() { ∙∙∙∙let name; }
-
15.2 Place 1 space before the leading brace. eslint:
space-before-blocks
// bad function test(){ console.log('test'); } // good function test() { console.log('test'); } // bad dog.set('attr',{ age: '1 year', breed: 'Bernese Mountain Dog', }); // good dog.set('attr', { age: '1 year', breed: 'Bernese Mountain Dog', });
-
15.3 Place 1 space before the opening parenthesis in control statements (
if
,while
etc.). Place no space between the argument list and the function name in function calls and declarations. eslint:keyword-spacing
// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
-
15.4 Set off operators with spaces. eslint:
space-infix-ops
// bad const x=y+5; // good const x = y + 5;
-
15.5 Do not add spaces inside parentheses. eslint:
space-in-parens
// bad function bar( foo ) { return foo; } // good function bar(foo) { return foo; } // bad if ( foo ) { console.log(foo); } // good if (foo) { console.log(foo); }
-
15.6 Do not add spaces inside brackets. eslint:
array-bracket-spacing
// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good const foo = [1, 2, 3]; console.log(foo[0]);
-
15.7 Add spaces inside curly braces. eslint:
object-curly-spacing
// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
-
15.8 Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per above, long strings are exempt from this rule, and should not be broken up. eslint:
max-len
Why? This ensures readability and maintainability.
// bad const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // bad $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.')); // good const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));
-
15.9 Require consistent spacing inside an open block token and the next token on the same line. This rule also enforces consistent spacing inside a close block token and previous token on the same line. eslint:
block-spacing
// bad function foo() {return true;} if (foo) { bar = 0;} // good function foo() { return true; } if (foo) { bar = 0; }
-
15.10 Avoid spaces before commas and require a space after commas. eslint:
comma-spacing
// bad var foo = 1,bar = 2; var arr = [1 , 2]; // good var foo = 1, bar = 2; var arr = [1, 2];
-
15.11 Enforce spacing inside of computed properties. eslint:
computed-property-spacing
// bad obj[foo ] obj[ 'foo'] var x = {[ b ]: a} obj[foo[ bar ]] // good obj[foo] obj['foo'] var x = { [b]: a } obj[foo[bar]]
-
15.12 Enforce spacing between functions and their invocations. eslint:
func-call-spacing
// bad func (); func (); // good func();
-
15.13 Enforce spacing between keys and values in object literal properties. eslint:
key-spacing
// bad var obj = { "foo" : 42 }; var obj2 = { "foo":42 }; // good var obj = { "foo": 42 };
-
15.14 Avoid trailing spaces at the end of lines. eslint:
no-trailing-spaces
-
15.15 Avoid multiple empty lines and only allow one newline at the end of files. eslint:
no-multiple-empty-lines
// bad var x = 1; var y = 2; // good var x = 1; var y = 2;
-
16.1 Leading commas: Nope. eslint:
comma-style
// bad const story = [ once , upon , aTime ]; // good const story = [ once, upon, aTime ]; // bad const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' }; // good const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers' };
-
Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether or not it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.
// bad - raises exception const luke = {} const leia = {} [luke, leia].forEach(jedi => jedi.father = 'vader') // bad - raises exception const reaction = "No! That's impossible!" (async function meanwhileOnTheFalcon() { // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` // ... }()) // bad - returns `undefined` instead of the value on the next line - always happens when `return` is on a line by itself because of ASI! function foo() { return 'search your feelings, you know it to be foo' } // good const luke = {}; const leia = {}; [luke, leia].forEach((jedi) => { jedi.father = 'vader'; }); // good const reaction = "No! That's impossible!"; (async function meanwhileOnTheFalcon() { // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` // ... }()); // good function foo() { return 'search your feelings, you know it to be foo'; }
-
18.1 Avoid single letter names. Be descriptive with your naming. eslint:
id-length
// bad function q() { // ... } // good function query() { // ... }
-
18.2 Use camelCase when naming objects, functions, and instances. eslint:
camelcase
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
-
18.3 Use PascalCase only when naming constructors or classes. eslint:
new-cap
// warn function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });
-
18.4 Do not use trailing or leading underscores. eslint:
no-underscore-dangle
Why? JavaScript does not have the concept of privacy in terms of properties or methods. Although a leading underscore is a common convention to mean “private”, in fact, these properties are fully public, and as such, are part of your public API contract. This convention might lead developers to wrongly think that a change won’t count as breaking, or that tests aren’t needed. tl;dr: if you want something to be “private”, it must not be observably present.
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda'; // good, in environments where WeakMaps are available // see https://kangax.github.io/compat-table/es6/#test-WeakMap const firstNames = new WeakMap(); firstNames.set(this, 'Panda');
To see our react rules
Open a Pull Request
updating the .eslintrc.json
. Also, update the README.md
following:
- X.X Rule description. eslint:
rule_clickable_eslint_rule_doc
Why? Why this rule is important
// bad incorrect example // good correct example