Walmart's guide to code style and best practices
- Types
- References & Variables
- Objects
- Arrays
- Destructuring
- Strings & Regular Expressions
- Functions
- Classes & Constructors
- Modules
- Iterators & Generators
- Comparison Operators & Equality
- Blocks & Whitespace
- Comments
- Commas & Semicolons
- Naming Conventions
- Forbidden Features
- React & JSX
- Acknowledgements
-
1.1 Primitives: When you access a primitive type you work directly on its value.
string
number
boolean
null
undefined
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
-
1.2 Complex: When you access a complex type you work on a reference to its value.
object
array
function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
-
1.3 Do not create primitive types using their constructors.
eslint:
no-new-wrappers
defined in:
rules/eslint/best-practices
// bad var booleanObject = new Boolean(false); var numberObject = new Number(1); var stringObject = new String("string"); // good var boolean = false; var number = 1; var string = "string";
Why?
Wrapping primitives in their constructor creates an object, which can have unintended side effects when making comparisons.
-
1.4 Do not use octals or octal escapes.
eslint:
no-octal
,no-octal-escape
defined in:
rules/eslint/best-practices
// bad var octal = 058; var escapedOctal = "\058"; // good var escapedHexadecimal = "\xA9";
Why?
Octal is deprecated in ES5.
-
1.5 Use
isNaN()
to check typeNaN
.eslint:
use-isnan
defined in:
rules/eslint/errors
// bad console.log(NaN === NaN); // false // good console.log(isNaN(NaN)); // true
Why?
NaN
is equal to nothing, including itself. UseisNaN
to check if a value isNaN
.
-
1.6 Only use valid strings for
typeof
expressions.eslint:
valid-typeof
defined in:
rules/eslint/errors
// bad typeof foo === "not a real type"; // good typeof foo === "number";
Why?
String comparisons to typeof can only evaluate as
true
if they are one of"undefined"
,"object"
,"boolean"
,"number"
,"string"
,"function"
, or"symbol"
.
-
2.1 Use only one variable declaration for each variable you wish to define.
eslint:
one-var: never
defined in:
rules/eslint/style
// bad const a, b; // good const a; const b;
Why?
Walmart code style preference.
-
2.2 Use
const
for all of your references; do not usevar
and avoid usinglet
.eslint:
prefer-const
defined in:
rules/eslint/es6
// bad var a = 1; let b = 2; // good const a = 1; const b = 2;
Why?
This ensures that you can't reassign your references, which can lead to bugs and difficult to comprehend code.
-
2.3 If you must reassign references, use
let
instead ofvar
.eslint:
no-var
defined in:
rules/eslint/es6
,configurations/es6-react
// bad var count = 1; if (true) { count += 1; } // good, use let let count = 1; if (true) { count += 1; }
Why?
let
is block-scoped rather than function-scoped likevar
. Read more in this blog post
-
2.4 Note that both
let
andconst
are block-scoped.// const and let only exist in the blocks they are defined in. { let a = 1; let b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
-
2.5 Always use
const
to declare variables. Do not initialze a variable toundefined
.eslint:
no-undef
,prefer-const
,no-undef-init
defined in:
rules/eslint/variables
,rules/eslint/es6
,rules/eslint/variables
// bad superPower = new SuperPower(); // good const superPower = new SuperPower(); // bad let notSureYet = undefined; // good let notSureYet;
Why?
Variables that aren't defined get hoisted to the global scope. Variables without a value at initialization are
undefined
by default.
-
2.6 Use one
const
declaration per variable.eslint:
one-var
defined in:
rules/eslint/style
// 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';
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.
-
2.7 Group all your
const
s and then group all yourlet
s.// bad let i, len, dragonball, items = getItems(), goSportsTeam = true; // bad let i; const items = getItems(); let dragonball; const goSportsTeam = true; let len; // good const goSportsTeam = true; const items = getItems(); let dragonball; let i; let length;
Why?
This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
-
2.8 Assign variables where you need them, but place them in a reasonable place.
// bad - unnecessary function call function checkName(hasName) { const name = getName(); if (hasName === 'test') { return false; } if (name === 'test') { this.setName(''); return false; } return name; } // good function checkName(hasName) { if (hasName === 'test') { return false; } const name = getName(); if (name === 'test') { this.setName(''); return false; } return name; }
Why?
let
andconst
are block scoped and not function scoped.
-
2.9 Don't chain variable assignments.
// 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); // undefined console.log(b); // 1 console.log(c); // 1 // good (function example() { let a = 1; let b = a; let c = a; }()); console.log(a); // undefined console.log(b); // undefined console.log(c); // undefined // the same applies for `const`
Why?
Chaining variable assignments creates implicit global variables.
-
2.10 Use braces to create blocks in
case
anddefault
clauses that contain lexical declarations (e.g.let
,const
,function
, andclass
).eslint:
no-case-declarations
defined in:
rules/eslint/best-practices
// bad switch (foo) { case 1: let x = 1; break; case 2: const y = 2; break; case 3: function f() {} break; default: class C {} } // good switch (foo) { case 1: { let x = 1; break; } case 2: { const y = 2; break; } case 3: { function f() {} break; } case 4: bar(); break; default: { class C {} } }
Why?
Lexical declarations are visible in the entire
switch
block but only get initialized when assigned, which only happens when itscase
is reached. This causes problems when multiplecase
clauses attempt to define the same thing.
-
2.11 Do not use magic numbers, except for
-1
,0
, and1
.eslint:
no-magic-numbers
defined in:
rules/eslint/best-practices
// bad function getTotal(price) { return price * 1.12; } // good function getTotal(price) { const taxRate = 1.12; return price * taxRate; }
Why?
Numbers should be assigned to constants to improve code readability and ease of refactoring. Magic numbers are allowed, however, in unit tests.
-
2.12 Do not reassign native variables.
eslint:
no-native-reassign
defined in:
rules/eslint/best-practices
// bad window = {}; undefined = 1;
Why?
There are several variables like
window
that are defined by the environment and should not be changed.
-
2.13 Do not declare the same variable more than once in the same scope.
eslint:
no-redeclare
defined in:
rules/eslint/best-practices
// bad var a = 3; var a = 10; // good var a = 3; a = 10;
Why?
Multiple declarations of the same variable can lead to confusion.
-
2.14 Do not leave expressions unused.
eslint:
no-unused-expressions
defined in:
rules/eslint/best-practices
// bad n + 1; 0; "string";
Why?
Unused expressions have no effect on the program.
-
2.15 Use operator shorthand whenever possible.
eslint:
operator-assignment
defined in:
rules/eslint/style
Use Instead of x += y x = x + y x -= y x = x - y x *= y x = x * y x /= y x = x / y x %= y x = x % y Why?
Operator assignment shorthand is more concise.
-
2.16 Do not use the same variable name in a catch clause as a variable in the outer scope.
eslint:
no-catch-shadow
defined in:
rules/eslint/variables
// bad var error = "error"; try { throw "problem"; } catch (error) { console.log(error); } // good var error = "error"; try { throw "problem"; } catch (e) { console.log(e); }
Why?
There is a bug in IE8 that can cause the
catch
argument to leak into the outer scope.
-
2.17 Do not use a label with the same name as a variable in scope.
eslint:
no-label-var
defined in:
rules/eslint/variables
// bad var first = 0; while (true) { first: while (true) { break first; } }
Why?
Labels with the same name as a variable can be confused.
-
2.18 Do not name a variable the same as a variable in the outer scope.
eslint:
no-shadow
defined in:
rules/eslint/variables
// bad var a = 3; function() { var a = 4; }
Why?
This can be confusing and the variable in the outer scope is no longer accessible from the inner scope.
-
2.19 Don't leave variables unused.
eslint:
no-unused-vars
defined in:
rules/eslint/variables
// bad var x = "unused"; /* end of script */
Why?
Unused variables are extra unnecessary clutter.
-
eslint:
no-use-before-define
defined in:
rules/eslint/variables
// bad console.log(a); var a = "test";
Why?
Variable declarations get hoisted to the top of the scope, so this is valid but confusing.
-
eslint:
no-const-assign
defined in:
rules/eslint/es6
// bad const doNotChange = "constant"; doNotChange = "mutated";
Why?
Changing a
const
assignment will result in a runtime error.
-
3.1 Use the literal syntax for object creation
eslint:
no-new-object
defined in:
rules/eslint/style
// bad const item = new Object(); // good const item = {};
Why?
Object literal syntax is more concise.
-
3.2 Use computed property names when creating objects with dynamic property names.
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true };
Why?
ES6 computed properties allow you to define all the properties of an object in one place.
-
3.3 Use object method shorthand.
eslint:
object-shorthand
defined in:
rules/eslint/es6
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; } }; // good const atom = { value: 1, addValue(value) { return atom.value + value; } };
Why?
ES6 object literal shorthand is more concise.
-
3.4 Use property value shorthand.
eslint:
object-shorthand
defined in:
rules/eslint/es6
const lukeSkywalker = "Luke Skywalker"; // bad const obj = { lukeSkywalker: lukeSkywalker }; // good const obj = { lukeSkywalker };
Why?
ES6 object literal shorthand is more concise.
-
3.5 Group your shorthand properties at the beginning of your object declaration.
const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
Why?
It is easier to tell which properties are using the shorthand.
-
3.6 Do not call
Object.prototype
methods directly, such ashasOwnProperty
,propertyIsEnumerable
, andisPrototypeOf
.// bad console.log(object.hasOwnProperty(key)); // good console.log(Object.prototype.hasOwnProperty.call(object, key)); // best const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope. /* or */ const has = require('has'); console.log(has.call(object, key));
Why?
These methods may be shadowed by properties on the object in question. Consider
{ hasOwnProperty: false }
. Or, the object may be a null object (Object.create(null)
).
-
3.7 Prefer the object spread operator over
Object.assign
to shallow-copy objects. Use the object rest operator to get a new object with certain properties omitted.// very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, {c: 3}); // this mutates `original` delete copy.a; // so does this // bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // good const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
Why?
Mutating objects can lead to mistakes and tough to solve bugs. Object spread operator is more concise than
Object.assign
. Read more about using object rest to omit properties from an object in this blog post.
-
3.8 Use dot notation when accessing properties.
eslint:
dot-notation
defined in:
rules/eslint/best-practices
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
Why?
Walmart code style preference.
-
3.9 Use bracket notation
[]
when accessing properties with a variable.const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
3.10 Do not extend native objects.
eslint:
no-extend-native
defined in:
rules/eslint/best-practices
// bad Object.prototype.a = "a"; // good var CustomObject = new Object(); CustomObject.prototype.a = "a";
Why?
Extending native or "built-in" features of the language can conflict with expectations of how these features work. If you need custom functionality, create a new instance of the feature first.
-
3.11 Do not use
__proto__
.eslint:
no-proto
defined in:
rules/eslint/best-practices
// bad var proto = obj.__proto__; // good var proto = Object.getPrototypeOf(obj);
Why?
__proto__
is deprecated in ES3.1.
-
3.12 Do not use the same key more than once in an object.
eslint:
no-dupe-keys
defined in:
rules/eslint/errors
// bad var obj = { myKey: "a", myKey: "b" }; // good var obj = { myKey: "a", myOtherKey: "b" };
Why?
Multiple keys with the same name can cause problems.
-
3.13 Do not call global objects as functions.
eslint:
no-obj-calls
defined in:
rules/eslint/errors
// bad Math(); JSON();
Why?
Global objects like
Math
andJSON
can look like class functions due to their capitalization. However, they are objects and cannot be invoked as functions.
-
3.14 Always add spacing around object curly braces.
eslint:
object-curly-spacing
defined in:
rules/eslint/style
// bad var product = {id: 1, name: "pokeball"}; // good var product = { id: 1, name: "pokeball" };
Why?
Walmart code style preference. Prettier compatible.
-
3.15 Separate object properties one per line or all on one line.
eslint:
object-property-newline
defined in:
rules/eslint/style
// bad var product = { id: 1, name: "pokeball", price: 12.95 }; // good var product = { id: 1, name: "pokeball", price: 12.95 }; // also good var product = { id: 1, name: "pokeball", price: 12.95 };
Why?
Walmart code style preference. Prettier compatible.
-
3.16 Only quote object property literals when needed.
eslint:
quote-props
defined in:
rules/eslint/style
// bad var product = { "id": 1, "name": pokeball }; // good var product = { id: 1, name: "pokeball", "category-id": 200 };
Why?
Walmart code style preference. Prettier compatible.
-
3.17 Dots should appear on the same line as their connecting property.
eslint:
dot-location
defined in:
rules/eslint/style
// bad var price = product. price; // good var price = product .price; // also good (but not for chaining) var price = product.price;
Why?
Walmart code style preference. Prettier compatible.
-
4.1 Use the literal syntax for array creation.
eslint:
no-array-constructor
defined in:
rules/eslint/style
// bad const items = new Array(); // good const items = [];
Why?
Array literals are more concise.
-
4.2 Use Array.push instead of direct assignment to add items to an array.
const someStack = []; // bad someStack[someStack.length] = "abracadabra"; // good someStack.push("abracadabra");
Why?
Array.push
is more concise.
-
4.3 Use array spreads
...
to copy arrays.// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
Why?
Array spreads is much more concise.
-
4.4 Do not use sparse arrays.
eslint:
no-sparse-arrays
rules/eslint/errors
// bad var items = [,,]; // good var items = new Array(3);
Why?
Sparse arrays can be confusing.
-
5.1 Use object destructuring when accessing and using multiple properties of an object.
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
Why?
Destructuring saves you from creating temporary references for those properties.
-
5.2 Use array destructuring.
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
Why?
Destructuring is more concise.
-
5.3 Use object destructuring for multiple return values, not array destructuring.
// bad function processInput(input) { return [left, right, top, bottom]; } // the caller needs to think about the order of return data const [left, __, top] = processInput(input); // good function processInput(input) { return { left, right, top, bottom }; } // the caller selects only the data they need const { left, top } = processInput(input);
Why?
You can add new properties over time or change the order of things without breaking call sites.
-
5.4 Do not use an empty pattern in a destructuring command.
eslint:
no-empty-pattern
defined in:
rules/eslint/best-practices
// bad var {} = foo; var {a: {}} = foo; // good var {a = {}} = foo;
Why?
Empty destructuring patterns do not create a variable and may be a typo on a default value assignment.
-
6.1 Use double quotes
""
or backticks ` for strings.eslint:
quotes
defined in:
rules/eslint/style
// bad const name = 'Aaron Rodgers'; // good const name = "Aaron Rodgers"; const name = `Aaron Rodgers`;
Why?
Walmart code style preference.
-
6.2 When programmatically building up strings, use template strings instead of concatenation.
eslint:
prefer-template
,no-useless-concat
defined in:
rules/eslint/es6
,rules/eslint/best-practices
// bad var str = "a" + "b"; // 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}?`; }
Why?
Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
-
6.3 Do not use multiline strings.
eslint:
no-multi-str
defined in:
rules/eslint/best-practices
// bad var str = "Multi \ Line"; // good var str = "Multi\n" + "Line"; // best var str = `Multi Line`;
Why?
Walmart code style preference.
-
6.4 Don't use empty character classes in regular expressions.
eslint:
no-empty-character-class
defined in:
rules/eslint/errors
// bad var regex = /^abc[]/;
Why?
An empty character class in a regular expression doesn't match anything and is likely a mistake.
-
6.5 Regular expressions must be valid.
eslint:
no-invalid-regexp
defined in:
rules/eslint/errors
// bad var regex = /[/; // good var regex = /[a-z]/;
Why?
Invalid regular expressions will throw an error when used.
-
6.6 Regular expressions should not contain multiple spaces.
eslint:
no-regex-spaces
defined in:
rules/eslint/errors
// bad var regex = /foo bar/; // good var regex = /foo {3}bar/;
Why?
It is easier to read the repeating character regular expression.
-
7.1 Use named function expressions instead of function declarations.
eslint:
func-style
defined in:
rules/eslint/style
// bad function foo() { } // good const foo = function () { };
Why?
Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module!
-
7.2 Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead.
eslint:
no-loop-func
defined in:
rules/eslint/best-practices
// bad for (var i = 0; i < 5; i++) { (function() { return i; })(); } // ok var a = function() {}; for (var i = 0; i < 5; i++) { a(); } // best for (let i = 0; i < 5; i++) { (function() { return i; })(); }
Why?
Using
let
to properly scope your variable to the block prevents hoisting errors. See this blog post for more information.
-
7.3 Never name a parameter
arguments
.// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
Why?
This will take precedence over the
arguments
object that is given to every function scope.
-
7.4 Use default parameter syntax rather than mutating function arguments.
// really bad function handleThings(opts) { // No! We shouldn't mutate function arguments. // Double bad: if opts is falsy it'll be set to an object which may // be what you want but it can introduce subtle bugs. opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
Why?
Default parameters syntax ensures a default value is applied only if an argument is not passed.
-
7.5 Always put default parameters last.
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
Why?
This prevents the necessity of passing
null
as an argument.
-
7.6 Never use the Function constructor to create a new function.
eslint:
no-new-func
defined in:
rules/eslint/best-practices
// bad var add = new Function("a", "b", "return a + b"); // still bad var subtract = Function("a", "b", "return a - b"); // good var add = function(a, b) { return a + b; };
Why?
Creating a function in this way evaluates a string similarly to
eval()
, which opens vulnerabilities.
-
7.7 Spacing in a function signature.
eslint:
space-before-function-paren
,space-before-blocks
defined in:
rules/eslint/style
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
Why?
Walmart code style preference.
-
7.8 Prefer the use of the spread operator
...
to call variadic functions.eslint:
prefer-spread
defined in:
rules/eslint/es6
// bad const x = [1, 2, 3, 4, 5]; console.log.apply(console, x); // good const x = [1, 2, 3, 4, 5]; console.log(...x); // bad new (Function.prototype.bind.apply(Date, [null, 2016, 08, 05])); // good new Date(...[2016, 08, 05]);
Why?
It's cleaner, you don't need to supply a context, and you can not easily compose
new
withapply
.
-
7.9 When you must use function expressions (as when passing an anonymous function), use arrow function notation.
eslint:
prefer-arrow-callback
,arrow-spacing
defined in:
rules/eslint/es6
// 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; });
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.
-
7.10 If the function body consists of a single expression, omit the braces and use the implicit return. Otherwise, keep the braces and use a
return
statement. Use parens only if there is more than one param.eslint:
arrow-parens
defined in:
rules/eslint/es6
// bad [1, 2, 3].map((number) => `A string containing the ${number}.`); // good [1, 2, 3].map(number => `A string containing the ${number}.`);
Why?
Parens around a single param is not required and adds unnecessary noise. Prettier compatible.
-
7.11 In case the expression spans over multiple lines, wrap it in parentheses for better readability.
// bad ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ); // good ['get', 'post', 'put'].map(httpMethod => ( Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ));
Why?
It is easier to see where a multi-line function starts and ends when wrapped this way.
-
7.12 Keep functions simple by limiting branching to 11 paths.
eslint:
complexity
defined in
rules/eslint/best-practices
function getFlagType(name) { if (name === BEST_SELLER) { return bestSeller; // 1st path } else if (name === CLEARANCE) { return clearance; // 2nd path } else if (name === OUT_OF_STOCK) { return outOfStock; // 3rd path } } // do not exceed 11 paths
Why?
Too many paths can be tough to wrangle. Consider refactoring.
-
7.13 Make sure a function either never returns a value or always returns a value.
eslint:
consistent-return
defined in:
rules/eslint/best-practices
// bad function(test) { if (test === true) { return true; } } // good function(test) { if (test === true) { return true; } return false; }
Why?
If some but not all branches of a function have an explicit return value, this may be a sign of a typo.
-
7.14 Do not use
bind()
unnecessarily.eslint:
no-extra-bind
defined in:
rules/eslint/best-practices
// bad var boundGetName = (function getName() { return "name"; }).bind({ name: "name" }); // good var boundGetName = (function getName() { return this.name; }).bind({ name: "name" });
Why?
Functions that do not make reference to
this
do not benefit from bindingthis
context.
-
7.15 Do not use
call()
orapply()
unnecessarily.eslint:
no-useless-call
defined in:
rules/eslint/best-practices
// bad foo.call(undefined, 1, 2, 3); foo.apply(undefined, [1, 2, 3]); // good foo.call(obj, 1, 2, 3); foo.apply(obj, [1, 2, 3]);
Why?
call()
andapply()
are slower than normal function invocation and should not be used when a regular function would suffice.
-
7.16 Do not make assignments in a return statement.
eslint:
no-return-assign
defined in:
rules/eslint/best-practices
// bad function doSomething() { return foo = bar + 2; } // good function doSomething() { foo = bar + 2; return foo; }
Why?
It can be confusing to understand if an equality check
===
was intended instead of an assignment when used in a return statement.
-
7.17 Only throw
Error
objects.eslint:
no-throw-literal
defined in:
rules/eslint/best-practices
// bad throw "error"; // good throw new Error();
Why?
Error
objects contain extra metadata about how they were thrown.
-
7.18 Don't use the same parameter more than once in a function definition.
eslint:
no-dupe-args
defined in:
rules/eslint/errors
// bad function doSomething(a, b, a) { console.log(`value of the second a: ${a}`); }
Why?
The second parameter with the same name will take precedence, which is probably an error.
-
7.19 Don't make an assignment on the exception parameter in a
catch
clause.eslint:
no-ex-assign
defined in:
rules/eslint/errors
try { doSomething(); } catch (e) { e = 10; }
Why?
Overwriting the exception variable will make it inaccessible.
-
7.20 Do not override function declarations.
eslint:
no-func-assign
defined in:
rules/eslint/errors
// bad function myFunction() {} myFunction = function() {};
Why?
Overriding a function declaration is likely a mistake.
-
7.21 Do not nest callbacks more than three deep.
eslint:
max-nested-callbacks
defined in:
rules/eslint/style
// bad callPlay(function() { // callback 1 snapToRodgers(function() { // callback 2 throwToJordy(function() { // callback 3 scoreTouchdown(function() { // callback 4 // win }); }); }); });
Why?
Nesting more than 3 callbacks can be difficult to read. Consider refactoring.
-
7.22 Do not use more than three parameters in a function call.
eslint:
max-params
defined in:
rules/eslint/style
// bad function doSomething(option1, option2, option3, option4) { return option1 + option2 + option3 + option4; } // good function doSomething(options) { const { option1, option2, option3, option4 } = options; return option1 + option2 + option3 + option4; }
Why?
It can be difficult to remember the order of many parameters. Pass an options object instead to handle large amounts of argument data.
-
7.23 Do not have more than 15 statements in a function.
eslint:
max-statements
defined in:
rules/eslint/style
// bad function doSomething() { var a = 1; // statement 1 var b = 2; // statement 2 var c = 3; // statement 3; // more statements here var o = 15; // statement 15; var p = 16; // statement 16; }
Why?
Prefer smaller functions. If number of statements exceeds 15, consider breaking the function up into smaller pieces.
-
8.1 Always use
class
. Avoid manipulatingprototype
directly.// bad function Queue(contents = []) { this.queue = [...contents]; } Queue.prototype.pop = function () { const value = this.queue[0]; this.queue.splice(0, 1); return value; }; // good class Queue { constructor(contents = []) { this.queue = [...contents]; } pop() { const value = this.queue[0]; this.queue.splice(0, 1); return value; } }
Why?
class
syntax is more concise and easier to reason about.
-
8.2 Use
extends
for inheritance.// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }
Why?
It is a built-in way to inherit prototype functionality without breaking
instanceof
.
-
8.3 Methods can return
this
to help with method chaining.// bad Jedi.prototype.jump = function () { this.jumping = true; return true; }; Jedi.prototype.setHeight = function (height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // good class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);
Why?
Method chaining allows for more concise code.
-
8.4 Avoid duplicate class members.
eslint:
no-dupe-class-members
defined in:
rules/eslint/es6
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }
Why?
Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug.
-
8.5 Do not allow
this
outside of classes and class-like objects.eslint:
no-invalid-this
defined in:
rules/eslint/best-practices
// bad var justARegularFunction = function() { this.a = "a" }; // good var ThisIsAClass = function() { this.a = "a" };
Why?
this
could be undefined if referenced outside of an object or class.
-
8.6 Always use parentheses when calling
new
on a constructor.eslint:
new-parens
defined in:
rules/eslint/style
// bad var search = new Search; // good var search = new Search();
Why?
Walmart code style preference.
-
8.7 Use
super()
when required in constructors.eslint:
constructor-super
defined in:
rules/eslint/es6
// bad class Shape { constructor() { super(); } } class Square extends Shape { constructor() {} } // good class Shape { constructor() {} } class Square extends Shape { constructor() { super(); } }
Why?
Derived classes must call
super()
and non derived classes must not.- 8.8 Do not modify class declaration variables.
eslint:
no-class-assign
defined in:
rules/eslint/es6
// bad class Component {} Component = undefined;
Why?
Classes can be reassigned, but should not be.
-
8.9 Do not call
this
beforesuper()
in a constructor.eslint:
no-this-before-super
defined in:
rules/eslint/es6
// bad class Square extends Shape { constructor() { this.sides = 4; super(); } } // good class Square extends Shape { constructor() { super(); this.sides = 4; } }
Why?
In a derived class, use of
this
beforesuper()
causes a reference error.
-
9.1 Always use modules (
import
/export
) over a non-standard module system.// bad const SearchUtil = require('./SearchUtil'); module.exports = SearchUtil.fetch; // ok import SearchUtil from './SearchUtil'; export default SearchUtil.fetch; // best import { fetch } from './SearchUtil'; export default fetch;
Why?
Module syntax is standard ES6.
-
9.2 Do not use wildcard imports.
// bad import * as SearchUtil from './SearchUtil'; // good import SearchUtil from './SearchUtil';
Why?
This makes sure you have a single default export.
-
9.3 Do not export directly from an import.
// bad // filename fetch.js export { fetch as default } from './SearchUtil'; // good // filename fetch.js import { fetch } from './SearchUtil'; export default fetch;
Why?
Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
-
9.4 Multiline imports should be indented just like multiline array and object literals.
// bad import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; // good import { longNameA, longNameB, longNameC, longNameD, longNameE, } from 'path';
Why?
The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas.
-
10.1 Don't use iterators. Prefer JavaScript's higher-order functions instead of loops like
for-in
orfor-of
.eslint:
no-iterator
defined in:
rules/eslint/best-practices
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 const sum = numbers.reduce((total, num) => total + num, 0); sum === 15;
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.
-
10.2 Generators must have their function signature spaced properly.
eslint:
generator-star-spacing
defined in:
rules/eslint/es6
// bad function * foo() { } const bar = function * () { } const baz = function *() { } const quux = function*() { } function*foo() { } function *foo() { } // very bad function * foo() { } const wat = function * () { } // good function* foo() { } const foo = function* () { }
Why?
function
and*
are part of the same conceptual keyword -*
is not a modifier forfunction
,function*
is a unique construct, different fromfunction
.
-
10.3 Do not negate the left hand side operand in
in
expressions.eslint:
no-negated-in-lhs
defined in:
rules/eslint/errors
// bad if (!key in object) // good if (!(key in object))
Why?
Negating the left hand operand in
in
expressions is likely a mistake.
-
10.4 Generators must contain the
yield
keyword.eslint:
require-yield
defined in:
rules/eslint/es6
// bad function* myGenerator() { return true; } // good function* myGenerator() { yield false; return true; }
Why?
yield
is required to pause the generator and pass a value to the generator'snext()
method.
-
11.1 Use
===
and!==
over==
and!=
.eslint:
eqeqeq
defined in:
rules/eslint/best-practices
// bad if (a == b) {} if (a != b) {} // good if (a === b) {} if (a !== b) {}
Why?
==
and!=
do type coercion which can cause difficult to spot bugs.
-
11.2 Conditional statements such as the
if
statement evaluate their expression using coercion with theToBoolean
abstract method and always follow these simple rules:- Objects evaluate to true
- Undefined evaluates to false
- Null evaluates to false
- Booleans evaluate to the value of the boolean
- Numbers evaluate to false if +0, -0, or NaN, otherwise true
- Strings evaluate to false if an empty string
''
, otherwise true
if ([0] && []) { // true // an array (even an empty one) is an object, objects will evaluate to true }
-
11.3 Use shortcuts for booleans, but explicit comparisons for strings and numbers.
// bad if (isValid === true) { // ...stuff... } // good if (isValid) { // ...stuff... } // bad if (name) { // ...stuff... } // good if (name !== '') { // ...stuff... } // bad if (collection.length) { // ...stuff... } // good if (collection.length > 0) { // ...stuff... }
Why?
Explicit comparisons for non-boolean values are more semantic.
-
11.4 Ternaries should not be nested and generally be single line expressions.
eslint:
no-nested-ternary
defined in:
rules/eslint/style
// bad const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null; // better const maybeNull = value1 > value2 ? 'baz' : null; const foo = maybe1 > maybe2 ? 'bar' : maybeNull; // best const maybeNull = value1 > value2 ? 'baz' : null; const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
Why?
Nested ternaries can make code more difficult to read.
-
11.5 Do not compare a variable to itself.
eslint:
no-self-compare
defined in:
rules/eslint/best-practices
// bad if (x === x) { doSomething(); }
Why?
This is usually a sign of a typo when refactoring.
-
11.6 Do not use Yoda conditions.
eslint:
yoda
defined in:
rules/eslint/best-practices
// bad if ("red" === color) // good if (color === "red")
Why?
Walmart code style preference.
-
11.7 Do not make assignments in conditional statements.
eslint:
no-cond-assign
defined in:
rules/eslint/errors
// bad if (results.sortBy = "price") // good if (results.sortBy === "price")
Why?
Assignments in a conditional statement are often a mistake when a comparison
===
was actually intended.
-
11.8 Do not use a constant expression or literal as a test condition.
eslint:
no-constant-condition
defined in:
rules/eslint/errors
// bad if (false) // good if (booleanTestCondition)
Why?
A constant expression does not necessitate a comparison.
-
11.9 Do not unecessarily cast a boolean variable.
eslint:
no-extra-boolean-cast
defined in:
rules/eslint/errors
// bad if (!!testConditional) // bad !!ternaryConditional ? ifTrue() : ifFalse (); // bad var tripleNegative = !!!booleanValue; // good var castBoolean = !!notBooleanValue; // good if (!notConditional)
Why?
This is just unnecessary.
-
12.1 Use braces only with multi-line blocks.
eslint:
curly
defined in:
rules/eslint/best-practices
// bad if (test) { return false; } // good if (test) return false;
Why?
Walmart code style preference. Prettier compatible.
-
12.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
defined in:
rules/eslint/style
// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
Why?
Walmart code style preference.
-
12.3 Use soft tabs set to 2 spaces.
eslint:
indent
,no-mixed-spaces-and-tabs
,no-trailing-spaces
defined in:
rules/eslint/style
// bad function foo() { ∙∙∙∙const name; } // bad function bar() { ∙const name; } // good function baz() { ∙∙const name; }
Why?
Walmart code style preference.
-
12.4 Place 1 space before the leading brace.
eslint:
space-before-blocks
defined in:
rules/eslint/style
// 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', });
Why?
Walmart code style preference.
-
12.5 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
defined in:
rules/eslint/style
// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
Why?
Walmart code style preference.
-
12.6 Set off operators with spaces.
eslint:
space-infix-ops
defined in:
rules/eslint/style
// bad const x=y+5; // good const x = y + 5;
Why?
Walmart code style preference.
-
12.7 End files with a single newline character.
eslint:
eol-last
defined in:
rules/eslint/style
// bad (function (global) { // ...stuff... })(this);
// bad (function (global) { // ...stuff... })(this);↵ ↵
// good (function (global) { // ...stuff... })(this);↵
Why?
Walmart code style preference.
-
12.8 Leave a blank line after blocks and before the next statement.
eslint:
no-multiple-empty-lines
defined in:
rules/eslint/style
// bad if (foo) { return bar; } return baz; // good if (foo) { return bar; } return baz; // bad const obj = { foo() { }, bar() { }, }; return obj; // good const obj = { foo() { }, bar() { }, }; return obj; // bad const arr = [ function foo() { }, function bar() { }, ]; return arr; // good const arr = [ function foo() { }, function bar() { }, ]; return arr;
Why?
Walmart code style preference.
-
12.9 Do not add spaces inside parentheses.
eslint:
space-in-parens
defined in:
rules/eslint/style
// bad function bar( foo ) { return foo; } // good function bar(foo) { return foo; } // bad if ( foo ) { console.log(foo); } // good if (foo) { console.log(foo); }
Why?
Walmart code style preference.
-
12.10 Avoid having lines of code that are longer than 100 characters (including whitespace). Note: URLs are exempt from this rule.
eslint:
max-len
defined in:
rules/eslint/style
// 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://walmart.com/", data: { name: "John" } }).done(() => console.log("Congratulations!")).fail(() => console.log("Error.")); // 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://walmart.com/", data: { name: "John" }, }) .done(() => console.log("Congratulations!")) .fail(() => console.log("Error."));
Why?
This ensures readability and maintainability.
-
12.11 Do not allow switch statements to "fall through".
eslint:
no-fallthrough
defined in:
rules/eslint/best-practices
// bad switch (action) { case POST: doSomething(); case GET: doSomething(); } // good switch (action) { case POST: doSomething(); break; case GET: doSomething break; }
Why?
Unintentional fallthroughs can cause unintended behavior. If a fallthrough is intentional, use the comment
// falls through
to indicate it is done purposefully.
-
12.12 Do not use labels except with loops or switch statements.
eslint:
no-labels
defined in:
rules/eslint/best-practices
// bad customBlock: { console.log("log this"); break customBlock; console.log("but not this"); } console.log("and then log this"); // good loopLabel: while (true) { break loopLabel; }
Why?
Labels outside of switch statements and loops are not well-known and can be confusing to understand.
-
12.13 Don't use unnecessary blocks.
eslint:
no-lone-blocks
defined in:
rules/eslint/best-practices
// bad if (foo) { bar(); { baz(); } } // good if (foo) { bar(); baz(); } // also ok if (foo) { bar(); { let i = 1; baz(i); } }
Why?
In ES5, blocks do not create new scope. In ES6, they are only useful when scoping
const
orlet
.
-
12.14 Don't use multiple spaces in a row.
eslint:
no-multi-spaces
defined in:
rules/eslint/best-practices
// bad if (a === b) { doSomething(); } // good if (a === b) { doSomething(); }
Why?
Walmart code style preference.
-
12.15 Don't use more than one
case
statement with the same name.eslint:
no-duplicate-case
defined in:
rules/eslint/errors
// bad switch (a) { case 1: break; case 2: break; case 1: break; }
Why?
Multiple
case
statements with the same is likely an error.
-
12.16 Don't leave block statements empty.
eslint:
no-empty
defined in:
rules/eslint/errors
// bad if (condition) { }
Why?
Empty blocks don't do anything.
-
12.17 Do not declare functions inside blocks.
eslint:
no-inner-declarations
defined in:
rules/eslint/errors
// bad if (test) { function doSomething(); } // good var doSomething; if (test) { doSomething = function() {}; }
Why?
Hoisting can cause unintended results.
-
12.18 Do not use irregular whitespace characters outside of strings.
eslint:
no-irregular-whitespace
defined in:
rules/eslint/errors
Invalid characters:
\u000B - Line Tabulation (\v) - <VT> \u000C - Form Feed (\f) - <FF> \u00A0 - No-Break Space - <NBSP> \u0085 - Next Line \u1680 - Ogham Space Mark \u180E - Mongolian Vowel Separator - <MVS> \ufeff - Zero Width No-Break Space - <BOM> \u2000 - En Quad \u2001 - Em Quad \u2002 - En Space - <ENSP> \u2003 - Em Space - <EMSP> \u2004 - Tree-Per-Em \u2005 - Four-Per-Em \u2006 - Six-Per-Em \u2007 - Figure Space \u2008 - Punctuation Space - <PUNCSP> \u2009 - Thin Space \u200A - Hair Space \u200B - Zero Width Space - <ZWSP> \u2028 - Line Separator \u2029 - Paragraph Separator \u202F - Narrow No-Break Space \u205f - Medium Mathematical Space \u3000 - Ideographic Space
Why?
Non-standard whitespace may be interpreted incorrectly and cause errors.
-
12.19 Do not write code that will be unreachable in a block.
eslint:
no-unreachable
defined in:
rules/eslint/errors
// bad function() { var x = 2; return x; x = 3; } while (true) { break; console.log("this is unreachable"); }
Why?
Unreachable code will never be executed and is likely a mistake.
-
12.20 Use one space after the colon and zero before in objects.
eslint:
key-spacing
defined in:
rules/eslint/style
// bad var obj = { a : 1, b:2 }; // good var obj = { a: 1, b: 2 };
Why?
Walmart code style preference.
-
12.21 Do not nest blocks more than 4 levels.
eslint:
max-depth
defined in:
rules/eslint/style
// bad function doSomething() { if (true) { // level 1 if (true) { // level 2 if (true) { // level 3 if (true) { // level 4 if (true) { // level 5 console.log("3deep5me"); } } } } } }
Why?
Consider refactoring if you need to go more than 4 levels deep in nesting.
-
12.22 Do not include an
if
block as the only statement in anelse
block.eslint:
no-lonely-if
defined in:
rules/eslint/style
// bad if (test) { doSomething(); } else { if (test2) { doSomethingElse(); } } // good if (test) { doSomething(); } else if (test2) { doSomethingElse(); }
Why?
Lonley
if
statements are better suited for anelse if
statement.
-
12.23 Do not add space between a function identifier and its application.
eslint:
no-spaced-func
defined in:
rules/eslint/style
// bad doSomething (stuff); // good doSomething(stuff);
Why?
Walmart code style preference.
-
12.24 Always include a space after semicolons that are not at the end of a line and never include a space before a semicolon.
eslint:
semi-spacing
defined in:
rules/eslint/style
// bad var x = 8 ; var x = 2;var y = 3; // good var x = 8; var x = 2; var y = 3;
Why?
Walmart code style preference.
-
12.25 Use spacing after unary words and never use spacing before/after unary nonwords.
eslint:
space-unary-ops
defined in:
rules/eslint/style
// bad var search = new[Search][0]; page ++; // good var search = new Search(); page++;
Why?
Walmart code style preference.
-
13.1 Use
/** ... */
for multi-line comments.// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ...stuff... return element; }
Why?
Walmart code style preference.
-
13.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.// 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; }
Why?
Walmart code style preference.
-
13.3 Use
// TODO:
to annotate solutions to problems.class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
-
13.4 Use valid JSDoc comments.
eslint:
valid-jsdoc
defined in:
rules/eslint/errors
// bad /** * Add two numbers. * @param {number} num The first number. * @returns The sum of the two numbers. */ function add(num1, num2) { return num1 + num2; } // good /** * Add two numbers. * @params {number} num1 The first number. * @params {number} num2 The second number. * @returns The sum of the two numbers. */ function add(num1, num2) { return num1 + num2; }
Why?
Valid JSDoc syntax is required for properly generated documentation.
-
14.1 Leading commas: Nope.
eslint:
comma-style
defined in:
rules/eslint/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', };
-
14.2 Additional trailing comma: Nope.
eslint:
comma-dangle
defined in:
rules/eslint/errors
// bad const hero = { firstName: 'Dana', lastName: 'Scully', }; const heroes = [ 'Batman', 'Superman', ]; // good const hero = { firstName: 'Dana', lastName: 'Scully' }; const heroes = [ 'Batman', 'Superman' ];
Why?
Walmart code style preference.
-
14.3 Semicolons required: Yup.
eslint:
semi
defined in:
rules/eslint/style
// bad (function () { const name = 'Skywalker' return name })() // good (function () { const name = 'Skywalker'; return name; }());
Why?
Walmart code style preference.
-
14.4 Don't use extra semicolons.
eslint:
no-extra-semi
defined in:
rules/eslint/errors
// bad var x = 5;; function myFunction() { }; // good var x = 5; var myFunction = function() { };
Why?
Only use semicolons once at the end of non-block lines.
-
14.5 Do not create confusing multiline statements.
eslint:
no-unexpected-multiline
defined in:
rules/eslint/errors
// bad var foo = bar (1 || 2).baz();
Why?
Omitting semicolons in some cases will cause multiple lines to be evaluated as one, which may not be the intended behavior.
-
15.1 Use camelCase when naming objects, functions, and instances.
eslint:
camelcase
defined in:
rules/eslint/style
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
Why?
Walmart code style preference.
-
15.2 Use PascalCase only when naming constructors or classes.
eslint:
new-cap
defined in:
rules/eslint/style
// bad 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', });
Why?
Walmart code style preference.
-
15.3 Don't save references to
this
. Use arrow functions or Function#bind.// bad function foo() { const self = this; return function () { console.log(self); }; } // bad function foo() { const that = this; return function () { console.log(that); }; } // good function foo() { return () => { console.log(this); }; }
Why?
Use of arrow functions or
bind
is more semantic and does not require declaring a new reference.
-
15.4 Use camelCase when you export-default a function.
function buildSearchQuery() { } export default buildSearchQuery;
Why?
Walmart code style preference.
-
15.5 Use PascalCase when you export a constructor / class / singleton / function library / bare object.
const SearchConfig = { filter: { } }; export default SearchConfig;
Why?
Walmart code style preference.
-
15.6 If the property/method is a
boolean
, useisVal()
orhasVal()
.// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
Why?
Accessor names should be descriptive of their action.
-
15.7 If
this
must be stored in a variable, name the variableself
.eslint:
consistent-this
defined in:
rules/eslint/style
// bad function doSomething() { const that = this; function doSomethingElse() { return that; } } // good function doSomething() { const self = this; function doSomethingElse() { return self; } }
Why?
Walmart code style preference.
-
15.8 Do not use restricted names.
eslint:
no-shadow-restricted-names
defined in:
rules/eslint/variables
// bad var undefined = true;
Why?
Just no.
-
15.9 Name files using dash-casing.
eslint:
filenames/match-regex
defined in:
rules/filenames
# bad myComponent.jsx # good my-component.jsx
Why?
Walmart file naming preference.
-
16.1 Do not use
alert
.eslint:
no-alert
defined in:
rules/eslint/best-practices
// bad alert("test"); confirm("Is this working?"); prompt("Why not?", "Because.");
Why?
Alerts are bad UI and should not be used.
-
16.2 Do not use
arguments.caller
orarguments.callee
.eslint:
no-caller
defined in:
rules/eslint/best-practices
// bad function foo(n) { arguments.callee(n - 1); }
Why?
These are deprecated features of the language and do not work in ES5 stict mode.
-
16.3 Do not use
eval()
.eslint:
no-eval
,no-implied-eval
,no-script-url
defined in:
rules/eslint/best-practices
// bad eval("var a = 0"); location.href = "javascript:void(0)";
Why?
The use of
eval()
is dangerous and can open your application up to security vulnerabilities.
-
16.4 Do not use sequences outside of
for
loops or without explicitly wrapping in parentheses.eslint:
no-sequences
defined in:
rules/eslint/best-practices
// bad if (doSomething(), !!test) // good for (var i = 0, j = 10; i < j; i++, j--)
Why?
Sequences used in non-standard ways can be difficult to read.
-
16.5 Do not use the
with
statement.eslint:
no-with
defined in:
rules/eslint/best-practices
// bad with (point) { r = Math.sqrt(x * x + y * y); } // good const r = ({x, y}) => Math.sqrt(x * x + y * y);
Why?
with
adds members of an object to the current scope, making it impossible to tell what a variable inside the block actually refers to.
-
16.6 Do not use
console
.eslint:
no-console
defined in:
rules/eslint/errors
// bad console.log("test"); console.warn("warning"); console.error("error");
Why?
Console logs should not exist in production code.
-
16.7 Do not use
debugger
statement.eslint:
no-debugger
defined in:
rules/eslint/errors
// bad function doSomething() { debugger; return true; }
Why?
Set breakpoints in your debugging tool instead.
-
16.8 Do not use control characters in regular expressions.
eslint:
no-control-regex
defined in:
rules/eslint/errors
// bad var pattern = /\x1f/; // good var pattern = /\x20/;
Why?
ASCII characters 0-31 are invisible characters rarely used in JavaScript and are probably an error if in a regular expression.
-
16.9 Do not use directive
"use strict"
.eslint:
strict
defined in:
rules/eslint/strict
// bad "use strict";
Why?
Walmart code is transpiled.
-
16.10 Do not use bitwise operators.
eslint:
no-bitwise
defined in:
rules/eslint/style
// bad var x = y | z; var x = y & z; var x = y ^ z; var x = ~ z; var x = y << z; var x = y >> 2; var x = y >>> z; x |= y; x &= y; x ^= y; x <<= y; x >>= y; x >>>=y;
Why?
Bitwise operators are seldom needed and can be confused with logical operators.
-
16.11 Do not use the
delete
operator on a variable.eslint:
no-delete-var
defined in:
rules/eslint/variables
// bad var x = 1; delete x;
Why?
delete
is meant to be used for removing a property from an object. Using it on a variable may cause unexpected behavior.
-
17.1 Use double quotes for JSX attributes.
eslint:
jsx-quotes
defined in:
rules/eslint/style
// bad <Component name='myComponent' /> // good <Component name="myComponent" />
Why?
Walmart code style preference.
-
17.2 Do not use deprecated methods.
eslint:
react/no-deprecated
defined in:
rules/react
// bad React.render(<MyComponent />, root); // good ReactDOM.render(<MyComponent />, root);
Why?
Deprecated methods will be removed in future versions of React.
-
17.3 Do not call
setState()
inside of thecomponentDidMount()
orcomponentDidUpdate()
lifecycle methods.eslint:
react/no-did-mount-set-state
,react/no-did-update-set-state
defined in:
rules/react
// bad class MyComponent extends React.Component { componentDidMount() { this.setState({ name: this.props.name.toUpperCase() }); } componentDidUpdate() { this.setState({ name: this.props.name.toUpperCase() }); } }
Why?
Updating the state after a component mount or update will trigger a second
render()
call.
-
17.4 Do not directly mutate
this.state
.eslint:
react/no-direct-mutation-state
defined in:
rules/react
// bad class MyComponent extends React.Component { componentWillMount: function() { this.state.name = this.props.name.toUpperCase(); } } // good class MyComponent extends React.Component { componentWillMount: function() { this.setState({ name: this.props.name.toUpperCase();= }); } }
Why?
-
17.5 Do not use
isMounted
.eslint:
react/no-is-mounted
defined in:
rules/react
// bad var MyComponent = React.createClass({ handleClick: function() { if (this.isMounted()) { return; } } });
Why?
isMounted
is not available to ES6 classes and will be deprecated.
-
17.6 Do not use unknown properties in JSX.
eslint:
react/no-unknown-property
defined in:
rules/react
// bad var myJSX = <MyComponent class="wont-work" />; // good var myJSX = <MyComponent className="will-work" />;
Why?
An unknown JSX property is probably a mistake.
-
17.7 Use ES6 class instead of
React.createClass()
.eslint:
react/prefer-es6-class
defined in:
rules/react
// bad var MyComponent = React.createClass({ render: // ... }); // good class MyComponent extends React.Component { render() { // ... } }
Why?
ES6 classes are the new and preferred method of creating a component.
-
17.8 Always validate prop types.
eslint:
react/prop-types
defined in:
rules/react
// bad const Button = ({ name }) => ( <button>{name}</button> ); // good const Button = ({ name }) => ( <button>{name}</button> ); Button.propTypes = { name: React.PropTypes.string.isRequired };
Why?
Prop types helps catch errors.
-
17.9 Make sure
React
is in scope when writing JSX.eslint:
react/react-in-jsx-scope
,react/jsx-uses-react
defined in:
rules/react
// bad var myJSX = (<span></span>); // good import React from "react"; var myJSX = (<span></span>);
Why?
JSX syntax requires
React
to compile.
-
17.10 Don't use a closing tag on a self-closing tag.
eslint:
react/self-closing-comp
defined in:
rules/react
// bad var MyComponent = <MyComponent></MyComponent>; // good var MyComponent = <MyComponent />;
Why?
Self-closing tags are more concise.
-
17.11 Wrap multiline JSX in parentheses.
eslint:
react/jsx-wrap-multilines
defined in:
rules/react
// bad const MyComponent = <div> <p>Test</p> </div>; // good const MyComponent = ( <div> <p>Test</p> </div> );
Why?
This improves readability.
-
17.12 Always write the value of a boolean attribute.
eslint:
react/jsx-boolean-value
rules/react
// bad const checkbox = <Checkbox checked />; // good const checkbox = <Checkbox checked={true} />;
Why?
This improves readability.
-
17.13 Align a tag's closing bracket with the opening bracket.
eslint:
react/jsx-closing-bracket-location
defined in:
rules/react
// bad <Button className="button" text="Button" /> // bad <Button className="button" text="Button" /> // good <Button className="button" text="button" />
Why?
Walmart code style preference.
-
17.14 Event handlers should be prefixed
handler
.eslint:
react/jsx-handler-names
defined in:
rules/react
// bad <MyComponent onClick={this.click} /> // good <MyComponent onClick={this.handleClick} />
Why?
Walmart code style preference.
-
17.15 Multiline props should be indented 2 spaces.
eslint:
react/jsx-indent-props
defined in:
rules/react
// bad <Button name="button" className="button" /> // good <Button name="button" className="button" />
Why?
Walmart code style preference.
-
17.16 Iterable elements should have a key prop.
eslint:
react/jsx-key
defined in:
rules/react
// bad list.map((item) => <li>{item}</li>); // good list.map((item, index) => <li key={index}>{item}</li>);
Why?
React rendering benefits from key assignments.
-
17.17 All components must be defined.
eslint:
react/jsx-no-undef
,react/jsx-uses-vars
defined in:
rules/react
// bad <MyComponent /> // good import MyComponent from "./my-component"; <MyComponent />
Why?
Undefined components will cause a
ReferenceError
at runtime.
-
17.18 JSX components should be named using PascalCase.
eslint:
react/jsx-pascal-case
defined in:
rules/react
// bad <myComponent /> // good <MyComponent />
Why?
This is to distinguish from native HTML tags.
The Walmart JavaScript Style Guide was inspired by: