Tooling
General ES6
Naming
Spacing and Syntax
Third party JS libraries
Typescript
Scoping and Initialization
Conditionals
Miscellaneous Code Smells
Resources
Tools to help your team comply with Electron coding standards.
Add the .editorconfig
file to the root of your project. Download and install the EditorConfig plugin on your text editor (if it does not natively support it).
More information about EditorConfig
To run ESLint manually, you will have to refer to the local version of ESLint in your project. You can do this one of two ways:
Use the npm script provided in the package
Note: This will run but it will output an NPM error. This is due to ESLint returning a non-zero exit code.
Reference the local ESLint file directly.
In addition to being able to lint manually, linting can also be run automatically via the use of git hooks. To use git hooks, either clone the template project (TBD) or:
Copy the package.json file
Run npm install
to install husky, Prettier, and lint-staged
Run git add
after making changes
Run git commit -m "Message"
. Prettier will automatically format the files and the linter will run, preventing commits if there are errors.
Also see the Prettier documentation for more information on formatting and linting with git hooks.
Do use ES6 functionality when possible.
Why? This keeps our codebase consistent, cleaner, more concise, and more readable.
Do use an eslint or tslint file for your code.
Do use the .editorconfig file provided [link here].
Do use the ES6 array methods, such as .forEach, .map, .filter in lieu of a regular JS for loop with conditionals.
ESLint: no-iterator, no-restricted-syntax
Why? This allows us to scan and understand intent
Why? It keeps our codebase more concise and more readable
Why? Array methods allow us to return a new array and keep the original one from being mutated.
Code Examples:
Do this:
Not this:
Do use implicit returns whenever working with a single statement returning an expression (especially with array methods).
ESLint: arrow-parens, arrow-body-style
Why? This makes it easier to read, especially for chained functions.
Code Examples:
Do this:
Not this:
Do import from a path in one place (I.e, all imports from @angular/core in one line versus two).
ESLint: no-duplicate-imports
Why? Easier to find an import since they’re grouped.
** Code Examples:**
Do this:
Not this:
Do use single quotes for strings.
ESLint: quotes
Do use template strings instead of concatenation.
ESLint: prefer-template, template-curly-spacing
Do use the spread operator instead of Object.assign for shallow copies.
ESLint: prefer-object-spread
Why? This prevents us from mutating the original object.
Code Examples:
Do this:
Not this:
Do use dot notation for properties of objects.
ESLint: dot-notation
Don’t use quotes around keys in a JSON object unless it’s a reserved keyword or contains a hyphen.
ESLint: quote-props
Code Examples:
Do this:
Not this:
Don’t use bracket notation to get properties of objects unless it's a reserved keyword, includes improper syntax (I.e., a hyphen), or is a variable.
Code Examples:
Do this:
Not this:
Don’t set the value of a parameter in a function call; assign it to a variable and then pass it as a parameter. (Example: multiplyNumbers(10, x _ 2) should contain a variable called secondNumber where secondNumber = x _ 2).
Why? It makes it less readable.
Why? It makes it harder to debug.
Code Examples:
Do this:
Not this:
Do use intuitive names for variables and functions to describe the intent (what it does) or what data it holds.
Code Examples:
Do this:
Not this:
Do use lowerCamelCase for variables and UpperCamelCase for classes.
Code Examples:
Do this:
Not this:
Don’t name variables a single letter.
ESLint: id-length
Code Examples:
Do this:
Not this:
Do put a space between parameters.
Code Example:
Do this:
Not this:
Do put a space between a keyword and parenthesis, but don’t put a space before the parenthesis in functions.
Code Examples:
Do this:
Not this:
Do put a space between parenthesis and curly braces in a function or code block.
Do use two spaces for tabs / indents.
ESLint: indent
Do place proper spacing when declaring variables.
ESLint: space-infix-ops
Code Examples:
Do this:
Not this:
Do terminate all lines with semicolons except code blocks (conditionals, iterators) and functions.
ESLint: semi
Do use curly braces around code blocks, including switch / case statements.
Why? This improves readability.
Why? This ensures the scope is correctly encapsulated.
Do put comments on their own lines.
Code Examples:
Do this:
Not this:
Do put a space between the // and the comment content.
Code Examples:
Do this:
Not this:
Do indent chained methods on a new line.
Do use trailing commas.
ESLint: comma-dangle
Why? It allows for more accurate git diffs.
Code Examples:
Do this:
Not this:
Don’t add multiple consecutive blank lines inside of code blocks except for one blank line to set apart nested code blocks.
ESLint: padded-blocks, no-multiple-empty-lines
Code Examples:
Do this:
Not this:
}
Do examine the reasons why you want to introduce another JavaScript library.
Do research ways to write the functionality without using a third party library.
Do install third party libraries using NPM and save them in the package.json file.
Do check the approved third party libraries list before installing it.
TSLint: import-blacklist could do: bootstrap, jQuery (only for Angular projects)
Do add polyfills or uncomment the polyfills in the polyfills.ts file to ensure cross-browser functionality.
Do use vanilla ES6 over lodash when possible.
Why? Using ES6 ensures we’re all on the same page and consistent.
Why? Installing lodash without utilizing the more customized functions adds bloat and dependencies to the codebase.
Consider using another third party library if it contains multiple pieces of functionality you need for the application versus one method.
Don’t mix jQuery in with Angular.
TLint: import-blacklist could do: bootstrap, jQuery (only for Angular projects)
Why? jQuery is a heavy library and adds a lot of bloat to the codebase.
Why? Angular has much of the same functionality baked in (i.e., animations, Ajax calls).
Why? Many of the reasons for integrating jQuery is for one method (i.e., the .toggle() ) which could easily be replicated with vanilla JavaScript or Angular Animations.
Why? jQuery and Angular event handling tends to clash with each other.
Don’t use JavaScript if you can use CSS to provide the same interaction (I.e., transitions).
Do use Typescript extensions for Angular and Sharepoint projects.
Consider creating models and interfaces to assign to variables instead of defaulting to a type of any.
Why? Creating models and interfaces allows us to prototype and extend classes.
Why? Creating models and interfaces acts as living documentation for the app so new developers know what properties belong on an object and how to use it.
Don’t use optional parameters in callbacks unless you mean it.
Why? It makes it difficult to tell what data is needed and what will be returned.
Why? You can pass in less arguments instead.
Don’t use types of String, Boolean, Number, and Object; instead use: string, boolean, number, object.
TSLint: no-construct
Why? The uppercase types refer to non-primitive objects.
Do use const for declaring most complex typed (I.e., objects, arrays, functions) variables that shouldn’t be reassigned.
ESLint: prefer-const, no-const-assign
Why? Preventing reassignment helps prevent bugs caused by reusing a variable.
Why? It keeps all declarations in one place so we know what kind of value to expect.
Why? Declaring variables with const adds intention to that variable and makes it more readable for the next developer.
Why? Declaring variables with const allows you to utilize block scoping.
Do use let for declaring primitive typed variables and variables that should be reassigned.
ESLint: no-var
Why? Declaring variables with let adds intention to that variable and makes it more readable for the next developer.
Why? Declaring variables with let allows you to utilize lexical scoping.
Do use arrow functions for maintaining block scoping, especially for anonymous and callback functions.
ESLint: prefer-arrow-callback, arrow-spacing
Why? When writing loops, we don’t have to use an IIFE / closure to maintain the current scope of the variables.
Why? It doesn’t change the scope that the this keyword exists in.
Do use the literal syntax (I.e., const obj = {} ) for declaring complex typed variables.
ESLint: no-new-object, no-array-constructor, no-new-func
Code Examples:
Do this:
Not this:
Do remove unused variables and imports.
Why? Leaving unused variables and imports in reduces readability.
Why? Leaving unused variables and imports in makes it hard to debug or determine which variable is used for a result in the program.
Don’t chain variable assignments.
Why? This creates global variables.
Code Examples:
Do this:
Not this:
Do group conditionals when nesting without an else statement.
Code Examples:
Do this:
Not this:
Do use guard clauses.
Code Example
Do this:
Not this:
Do use strict equality over loose equality.
ESLint: eqeqeq
Why? It checks for the value as well as the type.
Code Examples:
Do this:
Not this:
Do shortcut Booleans (I.e., if (var) instead of if (var === true) or if (!var) instead of if (var === null) )
Do use parenthesis to separate complex conditional statements with multiple operators.
ESLint: no-mixed-operators
Why? Improves readability.
Why? Ensures the conditional is executed as intended.
Code Examples:
Do this:
Not this:
Don’t use ternary statements for nested conditionals if you can help it (you might need to for Sharepoint).
Why? This is difficult to read and maintain.
Code Examples:
Do this:
Not this:
Don’t use ternary statements for assigning a Boolean value
Code Examples:
Do this:
Not this:
Don’t use an else statement when an if statement returns.
ESLint: no-else-return
Why? It is unnecessary lines of code since a return exits the current code block and if the statement is not true, then the code will continue executing.
Code Examples:
Do this:
Not this:
Do keep conditionals as flat as possible (don’t nest multiple conditionals if possible).
Why? Nested conditional statements and code blocks introduce cyclomatic complexity, making it difficult to read, understand, and maintain.
Code Examples:
Do this:
Not this:
Do try to avoid coercing a variable from one type to another.
Do avoid coercing a variable to another type and then back to the original type.
Do keep functions and classes small and simple – they should perform one action.
Why? This follows the single responsibility principle (SRP).
Why? It makes code readable and maintainable.
Why? It makes code reusable.
Why? It makes code testable.
Do use a debouncer and subscription on API calls on key events.
Why? It keeps the program from being too chatty.
Why? Using a subscription means we can cancel the previous subscription when we call the API again.
Do refactor similar code structures to utilize a reusable function.
Code Examples:
Do this:
Not this:
Do refactor code if you find yourself adding too many comments about what it does.
Why? Explaining what a piece of code does via comments indicates the code is too complex to be readable or understandable.
Why? Self documenting code is more valuable than lines of comments.
Don’t leave empty code blocks.
ESLint: no-empty
Why? Adds code bloat and clouds intention.
Code Examples:
Do this:
Not this:
Don’t duplicate / copy & paste a code block and change a few characters in order to reuse it.
Why? Violates DRY (Don’t Repeat Yourself) and makes it so you can’t easily maintain your codebase (with changes and bug fixes).
Why? We can refactor to create a more generic function and turn the changes into parameters; this makes it easier to test.
Don’t use anonymous functions (except for some callbacks in arrow functions).
Why? It makes debugging / tracing more difficult when using anonymous functions.
Code Examples:
Do this:
Not this:
Don’t use long parameter lists in functions.
ESLint: max-params
Why? It’s difficult to understand.
Why? It’s easy to omit a parameter or create inconsistencies.
Why? Long parameter lists are an indication the function is too complex / doing more than one thing.
Code Examples:
Do this:
Not this:
Don’t pass a value directly into a function call; assign it to a variable and pass the variable.
ESLint: no-magic-numbers
Why? Assigning a variable describes intent and makes the code more readable.
Code Examples:
Do this:
Not this: