ESLint Plugin marks part of code, which is against the esLint rule and suggests automatic fix.
EditorConfig for VS Code
Plugin that ensures VS Code respects the .editorconfig
settings.
GitLens — Git supercharged Better VS Code git integration.
Prettier - Code formatter Allows formatting the code using prettier directly in the IDE.
Jest Automatically runs jest tests, shows test results directly in the code, in the errors pane and in the Test Explorer sidebar. Allows to debug individual tests.
Code Spell Checker Plugin marks the typo errors.
Better Comments Plugin colorize special types of comment, ToDO, deprecated...
Markdown All in One Preview markdown, auto generate table of contents, etc.
Live Share Allow multiple people to collaborate on a repository remotely. May be good for reviews or pair programming.
(May depend on selected keymap or a platform.)
Ctrl+P
Open any file in project using a fuzzy search.
Ctrl+Shift+P
Execute any command (including plugin commands) by writing the name of it, with fuzzy search applied.
Shift+Alt+O
Organize imports - remove and sort.
Ctrl+Shift+I
Format document using default or configured formatter (make sure you have a Prettier plugin installed and set as default).
- Do not use names with
_
for private (or other) variables or functions. Such properties have theprivate
access modifiers to tell they are internal object properties.
-
Use correct data type, avoid
any
. If the type can't be determined, useunknown
instead. That will force you to use type guards to check the type before using the variable, making the code type safe. -
Use
const
orlet
instead ofvar
. Useconst
if the variable is not going to be reassigned. -
Use
type
aliases in repetitive data types. -
Avoid unnecessary comments. Instead, make the code cleaner and more readable, use proper naming.
-
Use the primitive types
number
,string
,boolean
instead of String, Boolean, Number. -
Don’t use
bind
to create functions. Bind always returnsany
, disabling type checking.// Use const curryAdd = (x: number) => add(111, x); curryAdd(333); // Ok and type checked // Instead of function add(x: number, y: number) { return x + y; } const curryAdd = add.bind(null, 111); curryAdd(333); curryAdd("333");
-
Use
type[]
instead ofArray<type>
and
const array: string[] = [];
instead of
const array = new Array<string>();
. -
Use
async
instead on completedCallback & failedCallback./* OK */ async function loadData(): Promise<Entity[]> {} /* WRONG */ function loadData(completedCallback: (data: Entity[]) => void, failedCallback: (err: string) => void): void {}
-
When calling multiple independent async functions (async loadA, async loadB), consider using
Promise.all
to allow parallel and fail-fast behavior./* OK - total processing time = max(time of loadA, time of loadB) */ async function loadData(): Promise<Entity[]> { const [result1, result2] = await Promise.all([loadA(), loadB()]); } /* WRONG - possible undhandled promise rejections, see https://stackoverflow.com/questions/45285129/any-difference-between-await-promise-all-and-multiple-await */ async function loadData(): Promise<Entity[]> { const [a, b] = [loadA(), loadB()]; const [resultA, resultB] = [await a, await b]; } /* OK, but total processing time = sum(time of loadA, time of loadB) */ async function loadData(): Promise<Entity[]> { const [resultA, resultB] = [await loadA(), await loadB()]; } /* OK, but total processing time = sum(time of loadA, time of loadB) */ async function loadData(): Promise<Entity[]> { await loadA(); await loadB(); }
-
Avoid the
new Promise()
antipattern unless you are wrapping a function with callbacks./* WRONG */ async function loadData(): Promise<Entity[]> { return new Promise(function (resolve, reject) { queryDb() .then(data => resolve(toEntities(data))) .catch(e => reject(e)); }); }
/* OK */ async function loadData(): Promise<Entity[]> { const data = await queryDb(); return toEntities(data); }
/* OK */ async function getAppImageAsync(path: string): Promise<string> { return new Promise((resolve, reject) => MobileCRM.Application.getAppImage(path, null, resolve, reject)); }
-
Use template literals instead of concatenation
"some text " + "another text"
./* OK */ async function error(): string { return `Ajax error for ${a} : ${this.status} `; } /* WRONG */ async function error(): string { return "Ajax error for " + a + " : " + this.status + " "; }
- If your code in one TS file has more than 500 rows, it's really hard to read it and understand it in the reasonable time. Think how to divide such class into smaller classes.
To enable full tree shaking in a library, add the following to the package.json
file:
"sideEffects": false
However, when you do this, make sure to add the ESLint rule:
"tree-shaking/no-side-effects-in-initialization": 2
This ensures that there are no side-effects in the library, such as globally initialized code that would run on import. By stripping these side-effects, the initialization will not run at runtime.
See common/package.json and common/.eslintrc.json for example configuration.