Skip to content
This repository has been archived by the owner on Mar 20, 2021. It is now read-only.

Latest commit

 

History

History
4421 lines (3433 loc) · 97.2 KB

styleguide.md

File metadata and controls

4421 lines (3433 loc) · 97.2 KB

Walmart JavaScript Style Guide

Walmart's guide to code style and best practices

Table of Contents

  1. Types
  2. References & Variables
  3. Objects
  4. Arrays
  5. Destructuring
  6. Strings & Regular Expressions
  7. Functions
  8. Classes & Constructors
  9. Modules
  10. Iterators & Generators
  11. Comparison Operators & Equality
  12. Blocks & Whitespace
  13. Comments
  14. Commas & Semicolons
  15. Naming Conventions
  16. Forbidden Features
  17. React & JSX
  18. Acknowledgements

Types

  • 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 type NaN.

    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. Use isNaN to check if a value is NaN.

  • 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".

⬆️ back to top

References & Variables

  • 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 use var and avoid using let.

    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 of var.

    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 like var. Read more in this blog post

  • 2.4 Note that both let and const 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 to undefined.

    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 consts and then group all your lets.

    // 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 and const 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 and default clauses that contain lexical declarations (e.g. let, const, function, and class).

    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 its case is reached. This causes problems when multiple case clauses attempt to define the same thing.

  • 2.11 Do not use magic numbers, except for -1, 0, and 1.

    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.

  • 2.20

    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.

  • 2.21

    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.

⬆️ back to top

Objects

  • 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 as hasOwnProperty, propertyIsEnumerable, and isPrototypeOf.

    // 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 and JSON 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.

⬆️ back to top

Arrays

  • 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.

⬆️ back to top

Destructuring

  • 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.

⬆️ back to top

Strings & Regular Expressions

  • 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.

⬆️ back to top

Functions

  • 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 with apply.

  • 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 binding this context.

  • 7.15 Do not use call() or apply() 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() and apply() 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.

⬆️ back to top

Classes & Constructors

  • 8.1 Always use class. Avoid manipulating prototype 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 before super() 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 before super() causes a reference error.

⬆️ back to top

Modules

  • 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.

⬆️ back to top

Iterators & Generators

  • 10.1 Don't use iterators. Prefer JavaScript's higher-order functions instead of loops like for-in or for-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, and Object.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 for function, function* is a unique construct, different from function.

  • 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's next() method.

⬆️ back to top

Comparison Operators & Equality

  • 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 the ToBoolean 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.

⬆️ back to top

Blocks & Whitespace

  • 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 and else, put else on the same line as your if 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 or let.

  • 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 an else 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 an else 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.

⬆️ back to top

Comments

  • 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.

⬆️ back to top

Commas & Semicolons

  • 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.

⬆️ back to top

Naming Conventions

  • 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, use isVal() or hasVal().

    // 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 variable self.

    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.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.

⬆️ back to top

Forbidden Features

  • 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 or arguments.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.

⬆️ back to top

React & JSX

  • 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 the componentDidMount() or componentDidUpdate() 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?

    Shared mutable state is the root of all evil.

  • 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.

⬆️ back to top

Acknowledgements

The Walmart JavaScript Style Guide was inspired by:

⬆️ back to top