All names and comments MUST be written in English.
The following naming conventions MUST be used:
Construct | Convention |
---|---|
package | lower-dash-case |
module exporting default class | UpperCamelCase |
all other modules | lowerCamelCase |
classes, interfaces, and type aliases | UpperCamelCase |
enums and enum value names | UpperCamelCase |
constants | UPPER_CASE_WITH_UNDERSCORES or lowerCamelCase |
variables | lowerCamelCase or _lowerCamelCase * |
parameters | lowerCamelCase or _lowerCamelCase * |
public properties | lowerCamelCase |
protected/private properties | _lowerCamelCase |
*: Variables and parameter names generally SHOULD NOT be prefixed with underscores, but this may be warranted in rare cases where two variables in nested scopes make sense to have the same name, while avoiding shadowing the outer variable.
The following naming conventions SHOULD be used:
Variable type | Convention |
---|---|
Deferred | dfd |
Promise | promise |
Identifier | id |
Numeric iterator | i , j , k , l |
String iterator (for-in) | key , k |
Event | event |
Destroyable handle | handle |
Error object | error |
Options arguments | options |
Origin, source, from | source |
Destination, target, to | target |
Coordinates | x , y , z , width , height , depth |
All others | Do not abbreviate |
- All names SHOULD be as clear as necessary, SHOULD NOT be contracted just for
the sake of less typing, and MUST avoid unclear shortenings and
contractions (e.g.
MouseEventHandler
, notMseEvtHdlr
orhdl
orh
). - Names SHOULD use American English (
en-us
) spelling. - Names representing an interface MUST NOT use "I" as a prefix (e.g.
Event
notIEvent
). - Abbreviations and acronyms SHOULD NOT be uppercase when used as a name (e.g.
getXml
notgetXML
). - Collections SHOULD be named using a plural form.
- Names representing boolean states SHOULD start with
is
,has
,can
, orshould
. - Names representing boolean states SHOULD NOT be negative (e.g.
isNotFoo
is unacceptable). - Names representing a count of a number of objects SHOULD start with
num
. - Names representing methods SHOULD be verbs or verb phrases (e.g.
getValue()
, notvalue()
). - Factories or non-constructor methods that generate new objects SHOULD use the verb "create".
- Magic numbers MUST either be represented using a constant or enum, or be prefixed
with a comment representing the literal value of the number (e.g.
if (event.keyCode === Keys.KEY_A)
orif (event.keyCode === /* "a" */ 97)
). - Const variables that are used as object property aliases SHOULD follow
lowerCamelCase
naming conventions (e.g.const { firstName = 'firstName'} = this.properties;
)
-
All variables which are not reassigned in the block SHOULD be declared with
const
:// correct const a = 1; // incorrect var a = 1; let a = 1;
-
All variables which are reassigned in the block SHOULD be declared with
let
:// correct for (let i = 0; i < items.length; i++) { } // incorrect for (var i = 0; i < items.length; i++) { }
-
All variable declarations SHOULD use one
const
orlet
declaration per variable. The exception to this rule is the initialization expression of afor
statement, and object/array destructuring (e.g. for imports). This prevents variable declarations being lost inside long lists that may also include immediate assignments:// correct const items = getItems(); const length = items.length; let i = 0; let item; // also right const items = getItems(); for (let i = 0, item; (item = items[i]); i++) { } // incorrect const items = getItems(), length = items.length; let i = 0, item;
-
Variable declarations SHOULD be grouped by declaration type;
const
first, thenlet
:// correct const items = getItems(); const length = items.length; let i = 0; let item; // incorrect const items = getItems(); let item; const length = items.length; let i = 0;
-
Variables SHOULD be declared where they are first assigned:
// correct render(): void { const items = this.getItems(); if (!items.length) { return; } for (let i = 0, item; (item = items[i]); i++) { this.renderItem(item); } } // incorrect render(): void { const items = this.getItems(); let i; let item; if (!items.length) { return; } for (i = 0; (item = items[i]); i++) { this.renderItem(item); } }
-
The most appropriate data types SHOULD be used in all cases (e.g. boolean for booleans, not number).
-
Strings MUST use single quotes.
-
Equality comparisons MUST use strict comparison operators, with the exception that comparisons matching null or undefined MAY use
== null
. -
When type coersion is necessary, it SHOULD be performed using the appropriate global function (not constructor):
// correct let myBoolean = Boolean(something); let myNumber = Number(something); let myString = String(something); // incorrect let myBoolean = !!something; let myNumber = +something; let myString = '' + something; // also incorrect (and doesn't produce primitives, so don't do it!) let myBoolean = new Boolean(something); let myNumber = new Number(something); let myString = new String(something);
-
When passing an anonymous function as an argument, arrow functions SHOULD be used. Implicit returns from arrow functions are allowed if they increase the code readability and the return value is not ignored:
// correct [ 1, 2, 3 ].forEach((value) => { console.log(value); }); const arr = [ 1, 2, 3 ].map((value) => value * 2); // incorrect [ 1, 2, 3 ].forEach((value) => console.log(value));
-
When functions are not anonymous arguments to a function, arrow functions SHOULD NOT be used:
// correct const fn = function (): string { return 'foo'; } // incorrect const fn = () => 'foo';
-
this
typing MUST be used if accessingthis
and SHOULD NOT be typed asany
. Use ofconst self = this;
SHOULD NOT be used to scope arrow functions and MAY only be used when there is a need to preseve context across a normalfunction
or IIFC.// correct function foo(this: SomeType) { this.arr.forEach((item) => { if (this.doSomething(item)) { console.log(item); } }); } // incorrect function foo(this: any) { this.dangerous(); } function foo() { const self = this; self.arr.forEach((item) => { if (self.doSomething(item)) { console.log(item); } }); }
-
All code SHOULD assume it will run in strict mode. ES Modules are always parsed in strict mode and TypeScript will automatically emit modules with the
'use strict';
prolog to help ensure that compatability. -
arguments.callee
MUST NOT be used. -
The
debugger
statement MUST NOT be used. -
The
eval
function MUST NOT be used. -
The
radix
parameter ofparseInt
MUST be used. -
There MUST NOT be unreachable code after
break
,catch
,throw
, andreturn
statements. -
All imports, variables, functions, and private class members MUST be used.
-
Avoid casts when possible. If a type declaration can solve the problem instead, prefer that over a cast:
// correct const something: Something = { // ... }; // incorrect const something = <Something> { // ... };
-
Usage of
<any>
casts SHOULD be documented:/* need to coerce to any, because of NodeJS typings */ const req: RootRequire = <any> require;
-
Variable declarations SHOULD NOT include an explicit type declaration if it can be easily and safely inferred on the same line.
// correct const count = 0; const message = ''; // incorrect const count: number = 0; const message: string = '';
-
Declarations for exported functions and public class methods SHOULD include an explicit return type declaration for clarity.
// correct export function foo(arg1: number, arg2: string): boolean { // ... return true; } // incorrect export function foo(arg1: number, arg2: string) { // ... return true; }
-
Constructor parameters MUST NOT use
public
andprivate
modifiers. -
Parameter flags
noImplicitAny
,noImplicitThis
andstrictNullChecks
must be enabled.
-
Class properties SHOULD be ordered alphabetically, case-insensitively, ignoring leading underscores, in the following order:
- private fields (properties)
- private methods
- static fields (properties)
- static methods
- constructor
- protected fields (properties)
- protected methods
- public fields (properties)
- public methods
-
Interface properties SHOULD be ordered alphabetically, case-insensitively, ignoring leading underscores, in the following order:
- constructor
- function call
- index signature
- properties (private, protected, then public)
- methods (private, protected, then public)
-
Module exports SHOULD be ordered alphabetically, case-insensitively, by identifier.
-
Module imports SHOULD be ordered alphabetically by module ID, starting with the package name. Module imports from the current package SHOULD come last. Module imports SHOULD NOT be ordered by variable name, due to potential confusion when destructuring is involved.
-
Functions SHOULD be declared before their use. The exceptions to this rule are functions exported from a module and methods of a class:
// correct function getItems(): Item[] { // ... } const items = getItems(); // also correct export function one(): void { two(); } export function two(): void { // ... } // incorrect const items = getItems(); function getItems(): Item[] { // ... }
-
Comments documenting code entities SHOULD be written in JSDoc format. Type information SHOULD NOT be included, since it should be possible to pick up from function signatures.
Example:
/** * Produces something useful and/or interesting. * * @param foo Indicates how useful something *should* be. * @param bar Indicates how interesting something *should* be. * @template T Some sort * @return Something useful and/or interesting. */ export function doSomethingInteresting<T>(foo: string, bar: T): SomethingInteresting { }
Note: That typescript services used to have a formatting issue when there was not a clear line break between the code block and additional parameters list. This has been resolved, though it is preferred to have a break between the comment block and the first
@param
. -
All exports and members of exported interfaces and classes SHOULD have a JSDoc code block documenting the function, class, method, type, variable, constant, or property. Internal methods MAY also include JSDoc code blocks.
-
JSDoc blocks SHOULD use markdown syntax for providing formatting:
/** * Blocks *SHOULD* use additional `markdown` syntax to make intellisense more expressive. */
-
The following block tags SHOULD be used as appropriate:
Block Tag Notes @param
Denotes an argument for a method or function. @return
A description of the return value. @template
A description of a generic slot.
-
Comments SHOULD be used to explain why something needs to be written, not what it does. If a "what" comment seems necessary, consider rewriting the code to be clearer instead. Comments summarizing entire blocks of code are permissible.
-
Comments indicating areas to revisit SHOULD start with
TODO
orFIXME
to make them easy to find. Ideally, such comments should only ever appear in personal/feature branches, but may be merged at maintainers' discretion. -
Single line comments MUST begin with a space, i.e.,
// comment
and not//comment
.
-
Files MUST use hard tabs for indentation. Spaces MAY be used for alignment (under the assumption that hard tabs align to 4 spaces).
-
Files MUST end with a single newline character.
-
Files MUST NOT have more than one consecutive blank line.
-
Lines SHOULD NOT exceed 120 characters in length.
-
Lines MUST NOT contain trailing whitespace.
-
Semicolons MUST be used.
-
Semicolons SHOULD NOT be preceded by a space.
-
Semicolons in
for
statements MUST be followed by a space.
-
Commas SHOULD be followed by a space or newline, and MUST NOT be preceded by a space.
-
Commas SHOULD NOT appear at the beginning of lines (i.e. no leading commas).
-
All other binary/ternary operators SHOULD be surrounded by a space on both sides, unless immediately followed by a newline, in which case the operator SHOULD precede the newline (except for
.
).
-
Colons in type definitions MUST be followed by a space or newline, and MUST NOT be preceded by a space.
-
Colons in object definitions SHOULD be followed by a space, and MUST NOT be preceded by a space.
-
Colons in
case
clauses SHOULD be followed by a newline, and MUST NOT be preceded by a space. The body of eachcase
clause SHOULD be indented one level deeper than thecase
clause, and SHOULD conclude with thebreak
keyword or a// fall through
comment.
-
Parentheses immediately preceding a block expression (e.g.
if
,for
,catch
) MUST be surrounded by a space on each side:// correct if (foo) { } // incorrect if(foo){ }
-
The opening brace of a code block MUST be written on the same line as its statement, preceded by a space:
// correct if (foo) { } // incorrect if (foo) { } if(foo){ }
-
All
if
,for
,do
,while
keywords MUST have opening and closing brackets. -
The opening and closing brackets on objects and arrays SHOULD be surrounded by whitespace on the inside of the object literal:
// correct let object = { foo: 'foo' }; let array = [ obj, 'foo' ]; let arrayOfObjects = [ { foo: 'foo' } ]; // incorrect let object = {foo: 'foo'}; let array = [obj, 'foo']; let arrayOfObjects = [{foo: 'foo'}];
-
Parentheses SHOULD NOT have space on the inside:
// correct if (foo) { doSomething(foo); } // incorrect if ( foo ) { doSomething( foo ); }
-
Anonymous functions SHOULD have a space between the
function
keyword and the opening parenthesis; named functions SHOULD NOT have a space between the function name and the opening parenthesis:// correct function myFunction() { return function () { }; } // incorrect function myFunction () { return function() { } }
-
Blocks with a single statement SHOULD NOT be written on the same line as the opening brace:
// correct if (foo) { bar; } // incorrect if (foo) { bar; }
-
Chained methods, when cannot be expressed on a single line, SHOULD line break after the first function call and before each subsequent function call in the chain, indented further than the original block:
// correct const promise = new Promise.resolve(() => { // return some value }) .then((result) => { // do something with result }) .catch((error) => { // do something with error }); const body = fetchResponse.text() .then((text) => { // do something with text }); // incorrect const promise = new Promise.resolve(() => { // return some value }).then((result) => { // do something with result }).catch((error) => { // do something with error }); const promise = new Promise .resolve(() => { // return some value }) .then((result) => { // do something with result }); const body = fetchResponse .text().then((text) => { // do something with text });
-
else
andwhile
keywords SHOULD be on their own line, not cuddled with the closing brace of the previousif
/do
block. This is consistent with the use of all other block statements and allows comments to be placed consistently before conditional statements, rather than sometimes-before, sometimes-inside:// correct if (foo) { } else if (bar) { } else { } do { } while (baz) // incorrect if (foo) { } else if (bar) { } else { } do { } while(baz)
-
Labels MUST only be used on
do
,for
,while
andswitch
statements.// correct loop: for (let i = 0; i < 10; i++) { break loop; } // incorrect console: console.log('1, 2, 3`);
-
Labels MUST be defined before usage.
// correct loop: for (let i = 0; i < 10; i++) { break loop; } // incorrect loop: for (let i = 0; i < 10; i++) { break loop; } (function() { for (let i = 0; i < 10; i++) { // label out of scope break loop; } })();