TypeScript
Best Coding Practices:
| Standard Area | Recommended Practice | Purpose / Example |
|---|---|---|
| Variable Declaration | Immutability: Use const by default. Use let only if reassignment is strictly needed. Never use var. |
Purpose: Makes code logic predictable; reduces side effects. |
| Booleans | Named as Questions: Boolean variables must strictly use prefixes like is, has, should, or can. |
Purpose: Immediate semantic understanding. Bad: const visible = trueGood: const isVisible = true |
| Asynchronous Logic | Async/Await: Prefer async/await syntax over .then() chains. |
Purpose: Makes async code look like synchronous code; easier to debug. Exception: Parallel execution using Promise.all. |
| Imports | Type Imports: Use import type { ... } when importing interfaces or types. |
Purpose: Helps the bundler remove non-code imports, reducing bundle size. Example: import type { User } from './types' |
| Arrays | Generics Syntax: Prefer Array<Type> for complex types and Type[] for primitives. |
Purpose: Improves readability. Primitive: string[]Complex: Array<Record<string, unknown>> |
| String Handling | Template Literals: Use backticks (`) for concatenation instead of +. |
Purpose: Cleaner syntax and easier multi-line strings. Example: `Hello ${name}` is better than 'Hello ' + name |
| Switch Statements | Exhaustiveness Check: Use a never type check in the default case of a switch statement. |
Purpose: Ensures that if you add a new case to a Union type, the compiler forces you to handle it in the switch. |
Best Linting Practises:
| Tool | Rule Type | Typical Setting |
|---|---|---|
| Prettier | Style / Formatting | Indentation: 2 or 4 spaces (No Tabs). Quotes: Single or Double (choose one). Semicolons: Always or Never (choose one). |
ESLint (@typescript-eslint) |
Code Quality / Best Practice | @typescript-eslint/no-unused-vars: Disallow unused variables.@typescript-eslint/explicit-function-return-type: (Optional but helpful) Require function return types.no-console: Disallow console.log (especially in production code). |
ESLint (eslint-plugin-import) |
Module / Import Quality | import/order: Enforce a consistent order for imports.import/no-unresolved: Ensure imports point to existing files. |
Recommended Extensions for VScode:
| Extension Name | Publisher | Function |
|---|---|---|
| ESLint | Dirk Baeumer | Integrates ESLint into VS Code, showing errors and warnings directly in the editor and providing quick fixes. Essential for linting enforcement. |
| Prettier – Code formatter | Esben Petersen | Formats code using Prettier. Essential for enforcing consistent code style. |
| EditorConfig for VS Code | EditorConfig | Maintains consistent coding styles across multiple developers and editors by using a .editorconfig file in the repository root. |
VS Code configuration file for Typescript Linting:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
Recommended TS Config file:
export = {
rules: {
'@typescript-eslint/ban-ts-comment': 'error',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-empty-object-type': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'@typescript-eslint/no-unsafe-function-type': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/ban-ts-comment': 'error',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/no-array-delete': 'error',
'@typescript-eslint/no-base-to-string': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-empty-object-type': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-for-in-array': 'error',
'no-implied-eval': 'off',
'@typescript-eslint/no-implied-eval': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/no-misused-promises': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-unsafe-argument': 'error',
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
'@typescript-eslint/no-unsafe-function-type': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-unsafe-unary-minus': 'error',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'error',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-wrapper-object-types': 'error',
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/prefer-namespace-keyword': 'error',
'prefer-promise-reject-errors': 'off',
'@typescript-eslint/prefer-promise-reject-errors': 'error',
'require-await': 'off',
'@typescript-eslint/require-await': 'error',
'@typescript-eslint/restrict-plus-operands': 'error',
'@typescript-eslint/restrict-template-expressions': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
'@typescript-eslint/unbound-method': 'error',
},
};
Scripts to add to package.json
"scripts": {
"type-check": "tsc --noEmit",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"format:check": "prettier --check \"**/*.{ts,tsx,json,css,md}\""
}
Commands to check on whether repository is following Lint:
npm run lint npm run format:check