backend-tslint-rules
v1.14.0
Published
Shared TSLint rules to enforce a consistent code style for backend development with TypeScript
Downloads
489
Maintainers
Readme
backend-tslint-rules
Shared TSLint rules to enforce a consistent code style for backend development with TypeScript
Please support this project by simply putting a Github star. Share this library with friends on Twitter and everywhere else you can.
The value of the software produced is directly affected by the quality of the codebase, and not every developer might
- be aware of the potential pitfalls of certain constructions in TypeScript,
- know that not every developer is as capable in understanding an elegant (but abstract) solution as the original developer.
For that purpose, we need to use static code analysis tools such as TSLint to check readability, maintainability, and functionality errors.
Although complying with these tools may seem to appear as undesired overhead or may limit creativity, it becomes easier for any new developers to read, preventing a lot of time/frustration spent figuring out the structure and characteristics of the code.
Containing a set of TSLint rules, backend-tslint-rules
has been compiled using many contributions
from colleagues, commercial/open-source projects and some other sources from the Internet, as well as years of development
using the [Angular] framework.
If you have questions, comments or suggestions, just create an issue on this repository. I'll try to revise and republish these rules with new insights, experiences and remarks in alignment with the updates on TSLint.
Note: The following set of rules depend on:
- TSLint v5.12.0
Table of contents:
- Getting started
- Usage
- Rules
- Contributing
- License
Getting started
Installation
You can install backend-tslint-rules
using npm
npm install backend-tslint-rules --save
Note: You should have already installed TSLint.
Usage
To use these TSLint rules, use configuration inheritance via the extends
keyword.
A sample configuration is shown below, where tslint.json
lives adjacent to your node_modules
folder:
{
"extends": ["backend-tslint-rules"],
"rules": {
// override tslint rules here
...
}
}
Rules
Class and Member design
- Do not use classes unless required.
"no-unnecessary-class": [
true,
"allow-constructor-only",
"allow-static-only",
"allow-empty-class"
]
- Do not specify the
public
keyword (this is the default accessibility level). private
andprivate static
members in classes should be denoted with theprivate
keyword.
"member-access": [
true,
"no-public"
]
- Member ordering should be in the following way:
- Public members should be ordered before private members.
- Static members should be ordered before instance members.
- Variables should be ordered before functions.
"member-ordering": [
true,
"public-before-private",
"static-before-instance",
"variables-before-functions"
]
- Always prefer readonly private members (maintain immutability).
"prefer-readonly": true
- Member overloads should be consecutive.
"adjacent-overload-signatures": true
- Always prefer unifying any two overloads into one, by using a union or an optional/rest parameter.
"unified-signatures": true
- Always prefer functions over
private
members that do not usethis
.
"prefer-function-over-method": [
true,
"allow-public",
"allow-protected"
]
- Do not use a class method outside of a method call.
"no-unbound-method": [true, "ignore-static"]
- Do not use the
this
keyword outside class context (including functions in methods).
"no-invalid-this": [
true,
"check-function-in-method"
]
- Do not use
this
in static methods.
"static-this": true
- Do not assign
this
to local variables.
"no-this-assignment": true
- Do not use blank constructors.
"unnecessary-constructor": true
- Do not invoke the
super
method twice in a constructor (except in branched statements or nested class constructors).
"no-duplicate-super": true
- Always prefer parentheses
()
when invoking a constructor via the new keyword.
"new-parens": true
- Do not define
new
for classes.
"no-misused-new": true
- Do not use the constructors of
String
,Number
, andBoolean
.
"no-construct": true
Interface design
- Do not define constructors for interfaces.
- Do not use empty interfaces.
"no-empty-interface": true
- Always prefer
foo(): void
overfoo: () => void
in interfaces and types.
"prefer-method-signature": true
- Always prefer an interface declaration over a type literal (
type T = { ... }
).
"interface-over-type-literal": true
Function design
- Functions should be defined right after the variable declarations.
- Do not use the built-in function constructor.
"function-constructor": true
- Do not reassign function parameters (maintain immutability).
"no-parameter-reassignment": true
- Do not use void expressions in statement position.
"no-void-expression": true
- Always prefer
return;
in void functions andreturn undefined;
in value-returning functions.
"return-undefined": true
- Do not invoke
arguments.callee
within a function, as it makes impossible various performance optimizations.
"no-arg": true
Anonymous functions
- Always prefer defining anonymous functions as fat-arrow/lambda
() => { }
functions.
"only-arrow-functions": true
- fat-arrow/lambda functions should have parenthesis
()
around the function parameters (except if removing them is allowed by TypeScript).
"arrow-parens": [
true,
"ban-single-arg-parens"
]
- Always prefer
() => x
over() => { return x; }
.
"arrow-return-shorthand": [
true,
"multiline"
]
- Always prefer just
f
overx => f(x)
.
"no-unnecessary-callback-wrapper": true
- Do not use unnecessary and/or misleading scope bindings on functions.
"unnecessary-bind": true
Async functions
- Always prefer marking
async
functions returning aPromise
.
"promise-function-async": true
- Do not use the unnecessary
async
(if the awaited value that is not aPromise
).
"await-promise": true
- Do not use the unnecessary
return await
.
"no-return-await": true
- Do not use floating
Promise
.
"no-floating-promises": true
Variable design
- Do not use a variable before declaring.
"no-use-before-declare": true
- Always prefer
const
keyword where appropriate, for values that should never change. - Avoid using
let
(maintain immutability).
"prefer-const": true
- Do not use the
var
keyword.
"no-var-keyword": true
- Do not use implied global variables.
- Do not define a variable on the global scope from within a smaller scope.
"no-shadowed-variable": [
true,
{
"temporalDeadZone": false
}
]
- Declare one variable at a time (except in loops).
"one-variable-per-declaration": [
true,
"ignore-for-loop"
]
- Do not use duplicate variable names in the same block scope.
"no-duplicate-variable": [
true,
"check-parameters"
]
- Do not use a
var
/let
statement or destructuring initializer to be initialized toundefined
.
"no-unnecessary-initializer": true
Requires and Imports
- Do not import modules that are not listed as a dependency in the project's
package.json
.
"no-implicit-dependencies": true
- Do not use
import
statements with side-effect.
"no-import-side-effect": true
- Always use the
import
statement keywords in alphabetical order.
"ordered-imports": [
true,
{
"import-sources-order": "case-insensitive",
"named-imports-order": "case-insensitive",
"grouped-imports": false
}
]
- Always use a single
import
statement per module.
"no-duplicate-imports": true
- Do not use
require
statements at all (use ES6-styleimport
statement instead).
"no-require-imports": true
- Do not use default imports and exports in ES6-style modules.
"no-default-import": true,
"no-default-export": true
- Do not use
/// <reference path=> imports
statements at all (use ES6-styleimport
statement instead).
"no-reference": true
Types
- Always prefer defining the return type of functions, methods and property declarations explicitly.
- Types should be used whenever necessary (no implicit
any
).
"typedef": [
true,
"call-signature",
"property-declaration"
]
- Always prefer type inference over explicit type declaration (except for function return types).
"no-inferrable-types": true
- Do not use the default type arguments explicitly.
"use-default-type-parameter": true
- Meanwhile, avoid type assertion for object literals.
"no-object-literal-type-assertion": true
- Always prefer the use of
as Type
for type assertions over<Type>
.
"no-angle-bracket-type-assertion": true
- Do not use unnecessary type assertions.
"no-unnecessary-type-assertion": true
- Always prefer writing an interface or literal type with just a call signature as a function type.
"callable-types": true
- Do not use the
null
keyword, always returnundefined
instead of anull
reference.
"no-null-keyword": true
- Do not use non-null assertions.
"no-non-null-assertion": true
- Arrays should be defined as
Array<type>
instead oftype[]
.
"array-type": [
true,
"generic"
]
Objects
- Always prefer ES6 object spread operator whenever possible.
"prefer-object-spread": true
- Always prefer ES6 object literal shorthand whenever possible.
"object-literal-shorthand": true
- Always prefer object property names using literals whenever possible.
"object-literal-key-quotes": [
true,
"as-needed"
]
- Do not use string literal property access.
"no-string-literal": true
Strings
- Always prefer single-quotes
''
for all strings, and use double-quotes""
for strings within strings.
"quotemark": [
true,
"single",
"avoid-template",
"avoid-escape"
]
- Always prefer template expressions over string literal concatenation.
"prefer-template": true
- Do not use string templates outside template strings (``).
"no-invalid-template-strings": true
Operators
- Always prefer using
===
and!==
operators whenever possible.
==
and!=
operators do type coercion, which can lead to headaches when debugging code.
"triple-equals": [
true,
"allow-null-check"
]
- Always prefer explicit
+= 1
and-= 1
pre-unary operators over++i
and--i
.
"increment-decrement": [
true,
"allow-post"
]
- Always prefer using operands of the same type with the `+`` operator.
"restrict-plus-operands": true
- In a binary expression, a literal should always be on the right-hand side.
"binary-expression-operand-order": true
- Do not use the
delete
operator with dynamic key expressions.
"no-dynamic-delete": true
- Always prefer using
isNan
function to checkNaN
references.
"use-isnan": true
- Assignment expressions inside of the condition block of
if
,while
, anddo while
statements should be avoided.
"no-conditional-assignment": true
Conditional statements
- Always prefer conditional expression over a standard
if
statement.
"prefer-conditional-expression": [
true,
"check-else-if"
]
- Do not compare to two equal variables/literals as operands (ex:
3 === 3
,someVar === someVar
).
"no-tautology-expression": true
- Do not compare to a boolean literal (ex:
x === true
).
"no-boolean-literal-compare": true
- Do not use else blocks ending with a
break
,continue
,return
orthrow
statement.
"unnecessary-else": true
- Do not use any always truthy/falsy condition in boolean expressions (except right-hand operand
&&
or||
).
"strict-boolean-expressions": [
true,
"allow-undefined-union",
"allow-string",
"allow-enum",
"allow-number",
"allow-mix",
"allow-rhs"
]
for
statement
- Always prefer
while
loop over a standardfor
loop without initializer, incrementor and/or termination condition.
"prefer-while": true
- Always prefer
for-of
loop over a standardfor
loop.
"prefer-for-of": true
- Filter
for-in
statements with anif
statement (this prevents accidental iteration over properties inherited from an object???s prototype).
"forin": true
- Do not iterate over an array with a
for-in
loop.
"no-for-in-array": true
switch
statement
- Each switch statement should have a default case.
"switch-default": true
- Each switch case except default should end with
break
,return
, orthrow
.
"no-switch-case-fall-through": true
- Do not use duplicate switch cases.
"no-duplicate-switch-case": true
try
statement
- Do not use control flow statements, such as
return
,continue
,break
andthrows
infinally
blocks.
"no-unsafe-finally": true
Maintainability
- Use UTF-8 encoding.
"encoding": true
- Limit the level of complexity (cyclomatic complexity) in a function/method by 20 branches.
"cyclomatic-complexity": [
true,
20
]
- Files should not exceed 1500 lines of code.
"max-file-line-count": [true, 1500]
- Keep the length of each line under 140 characters.
"max-line-length": [
true,
140
]
- Use 2 spaces for indentation.
"indent": [
true,
"spaces",
2
]
- All files should end in a new line.
"eofline": true
Layout
Curly braces
Always Use curly braces.
"curly": true
Whitespace
Whitespaces should be used in the following circumstances:
- All branching statements (
if
/else
/for
/while
) should be followed by one space. - Variable declarations should be separated by one space around the type specification and equals token.
- There should be one space between the typecast and its target.
- All operators except the period
.
, left parenthesis(
, and left bracket[
should be separated from their operands by one space. - There should be no space between the unary/incremental operators
!x, -x, +x, ~x, ++x, --x
and its operand. - There should be one space between the type operators
|
,&
and its operand. - There should be one space after the left curly brace
{
and before the right curly brace}
containingimport
statement keywords. - Each separator (
,
,;
) in the control part of afor
statement should be followed with one space. - There should be no space after the rest/spread operator
...
. - The left curly brace
{
followed by a right parenthesis)
should always separated by one space.
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-module",
"check-separator",
"check-rest-spread",
"check-type",
"check-typecast",
"check-type-operator",
"check-preblock"
]
- For each call signature, index signature, parameter, property declaration and variable declaration;
- There should be no space between the parameter and the colon
:
indicating the type declaration. - There should be one space between the colon
:
and the type declaration.
- There should be no space between the parameter and the colon
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
},
{
"call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
}
]
- For each function, class member and constructor;
- There should be no space between the name of the function/member and the left parenthesis
(
of its parameter list.
- There should be no space between the name of the function/member and the left parenthesis
- For each fat-arrow/lambda function;
- There should be one space between the right parenthesis
)
and the=>
.
- There should be one space between the right parenthesis
"space-before-function-paren": [
true,
{
"anonymous": "never",
"named": "never",
"asyncArrow": "always",
"method": "never",
"constructor": "never"
}
]
- There should be no space within parenthesis.
"space-within-parens": 0
- Put one space between the
import
statement keywords.
"import-spacing": true
- Do not use trailing whitespaces at the end of a line
"no-trailing-whitespace": true
Empty lines
Empty lines improve code readability by allowing the developer to logically group code blocks.
- There should be an empty line before the return statement.
"newline-before-return": true
- There should be a separate line for each chained method call.
"newline-per-chained-call": true
- For each function, anonymous function, class member, constructor,
else
,catch
andfinally
statements;- There should be one space between the right parenthesis
)
and the left curly{
brace that begins the statement body.
- There should be one space between the right parenthesis
- For each fat-arrow/lambda function;
- There should be one space between the
=>
and the left curly brace{
that begins the statement body.
- There should be one space between the
else
statements should indented to align with the line containing the closing brace for theif
statement.catch
andfinally
statements should indented to align with the line containing the closing brace for thetry
statement.
"one-line": [
true,
"check-open-brace",
"check-whitespace",
"check-else",
"check-catch",
"check-finally"
]
- Do not use more than one empty line in a row.
"no-consecutive-blank-lines": [
true,
1
]
Alignment
- A semicolon should be placed at the end of every simple statement (except at the end of bound class methods).
"semicolon": [
true,
"always",
"strict-bound-class-methods"
]
- Vertically align elements, members, parameters and statements (helps maintain a readable, consistent style in your codebase).
"align": [
true,
"elements",
"members",
"parameters",
"statements"
]
- Do not use trailing commas in array and object literals, destructuring assignments, function typings, named imports/exports and function parameters.
"trailing-comma": [
true,
{
"multiline": "never",
"singleline": "never",
"esSpecCompliant": true
}
]
Naming
Files
- Files should be in kebab-case.
"file-name-casing": [
true,
"kebab-case"
]
Classes and Interfaces
- Class and interface names should be in PascalCase.
"class-name": true
- Interface names should not have an
I
prefix.
"interface-name": [
true,
"never-prefix"
]
Variables and Functions
- All variable, and function names should be in camelCase.
- All variables with UPPER_CASE names must be const.
- Do not use trailing underscore
_
characters.
"variable-name": [
true,
"check-format",
"allow-leading-underscore",
"require-const-for-all-caps",
"ban-keywords"
]
Documentation
- Always prefer single-line or JSDoc comments.
"comment-type": [
true,
"singleline",
"doc"
]
Inline Comments
- Always prefer
//
for all inline comments. - There should be one space before the comment.
"comment-format": [
true,
"check-space"
]
JSDoc Comments
- JSDoc comments should start with
/**
and end with*/
.
"jsdoc-format": [
true,
"check-multiline-start"
]
- Do not use redundant JSDoc comments.
"no-redundant-jsdoc": true
- Do not use the
// @ts-ignore
comments.
"ban-ts-ignore": true
Misc
- Do not use the
console
method (such messages are considered to be for debugging purposes and therefore might ship to the production environment).
"no-console": [
true,
"log",
"debug",
"info",
"time",
"timeEnd",
"trace"
]
- Do not use the
debugger
statement (this might cause the environment to stop execution and start up a debugger, if not omitted on the production code).
"no-debugger": true
- Do not use the
eval
function (usingeval
on untrusted code might open a program up to several different injection attacks).
"no-eval": true
- Do not throw plain strings or concatenations of strings (because only
Error
s produce proper stack traces).
"no-string-throw": true
- Do not use namespaces (using
namespace {}
is outdated).
"no-namespace": true
- Do not use internal modules (using
module {}
is outdated).
"no-internal-module": true
- Always prefer decimal literals beginning with
0
(instead of.
). - Avoid decimal literals ending with a trailing
0
.
"number-literal-format": true
- Always prefer the
radix
parameter to be specified when callingparseInt
.
"radix": true
- Do not leave unused expressions in the code.
"no-unused-expression": [
true,
"allow-fast-null-checks"
]
- Do not use empty blocks
{}
in the code.
"no-empty": true
- Do not use missing elements in arrays.
"no-sparse-arrays": true
- Do not use comma operator.
"ban-comma-operator": true
Contributing
If you want to file a bug, contribute some code, or improve documentation, please read up on the following contribution guidelines:
Thanks to
License
The MIT License (MIT)
Copyright (c) 2018 Burak Tasci