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 = true
Good: 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.
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"
  }
}

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