Best Practices Angular - JU-DEV-Bootcamps/ERAS GitHub Wiki

This document outlines the best practices and coding standards to ensure consistency, maintainability, and scalability in our Angular 19 project. It covers folder structure, Angular CLI usage, modular architecture, and other key guidelines for writing clean, efficient code.

1. Consistent Folder Structure

A consistent folder structure improves project organization and collaboration. Arrange your files logically by separating components, services, modules, and other resources into dedicated directories.

/src
  /app
    /components
      /header
        header.component.ts
        header.component.html
        header.component.css
    /services
      data.service.ts
    /modules
      main.module.ts

2. Use Angular CLI

Leverage Angular CLI to generate components, services, modules, and more. It helps enforce best practices, reduces human error, and standardizes project setup.

ng new my-angular-app
ng generate component header
ng generate service data

3. Modular Architecture

Break your application into smaller, reusable modules. Each module should serve a well-defined purpose and responsibility.

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, SharedModule, UserModule],
  bootstrap: [AppComponent]
})
export class AppModule {}

4. Single Responsibility Principle (SRP)

Ensure each component or service has a single responsibility. This makes it easier to maintain, test, and extend the code.

Bad Example:

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html'
})
export class UserComponent {
  fetchUserData() { ... }
  displayUserData() { ... }
  updateUserData() { ... }
}

Good Example:

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html'
})
export class UserComponent {
  displayUserData() { ... }
}

5. Meaningful Naming Conventions

Use descriptive, consistent names for files, classes, variables, and functions to enhance code readability.

Bad Example:

const x = 10;

Good Example:

const itemCount = 10;

6. Component Structure

Organize components with a consistent structure that includes separate files for templates, styles, and TypeScript logic.

/header
  header.component.ts
  header.component.html
  header.component.css

7. Strict Mode

Enable strict mode for better type-checking, linting, and overall code quality. This is enabled by default in Angular 19.

{
  "angularCompilerOptions": {
    "strict": true
  }
}

8. Standalone Components (Angular 19+)

Leverage standalone components where appropriate to avoid unnecessary modules. This improves modularity and reduces complexity.

@Component({
  selector: 'app-header',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent {}

9. Use of RxJS Operators

Follow best practices when using RxJS to manage asynchronous operations. Always unsubscribe when necessary and use appropriate operators.

10. ESLint and Prettier Configuration

Ensure consistent code formatting and style by using ESLint and Prettier. Below is a configuration example:

ESLint Configuration:

{
  "extends": ["eslint:recommended", "plugin:@angular-eslint/recommended"]
}

Prettier Configuration:

{
  "singleQuote": true,
  "trailingComma": "es5"
}

11. Dependency Management

Regularly update dependencies to ensure compatibility with Angular 19. Verify all dependencies, such as TypeScript and RxJS, are compatible with the latest Angular version.

npm install [email protected] --save-dev

12. Node.js and nvm (Node Version Manager)

Node.js Version Management

It's important to ensure that all developers are using the same version of Node.js to avoid discrepancies between environments. To manage Node versions effectively, we recommend using nvm (Node Version Manager). This allows each developer to easily switch between Node versions for different projects and ensures consistency across the team.

How to Set Up nvm

  1. Install nvm: Follow the instructions from the official nvm repository to install it on your machine.

  2. Install Node.js: Once nvm is installed, you can install the required Node version for the project (for example, Node 18.x, which is recommended for Angular 19).

    nvm install 18
  3. Use the Installed Version: Set the installed version as the default for your terminal sessions.

    nvm use 18
  4. Check the Node Version: Verify the Node version you're using with:

    node -v
  5. Setting Default Version: You can set a default version of Node.js for all future terminal sessions using:

    nvm alias default 18

By using nvm, we ensure that everyone on the team uses the correct version of Node.js that is compatible with the Angular 19 ecosystem and our project's dependencies.


TypeScript Rules for Angular

TypeScript Configuration

Strict Mode

Enable strict type-checking options to catch more errors at compile time.

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}

Module Resolution

Ensure consistent module resolution.

{
  "compilerOptions": {
    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "@app/*": ["src/app/*"]
    }
  }
}

Target and Lib

Specify the ECMAScript target and library.

{
  "compilerOptions": {
    "target": "es2015",
    "lib": ["es2015", "dom"]
  }
}

TypeScript Linting Rules

Type Annotations

Enforce type annotations for function parameters and return types.

{
  "@typescript-eslint/explicit-module-boundary-types": "error",
  "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }]
}

No Implicit Any

Disallow the use of implicit any types.

{
  "@typescript-eslint/no-explicit-any": "error"
}

No Unused Variables

Disallow unused variables and parameters.

{
  "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
}

Interface and Type Naming

Enforce consistent naming conventions for interfaces and types.

{
  "@typescript-eslint/naming-convention": [
    "error",
    {
      "selector": "interface",
      "format": ["PascalCase"],
      "custom": {
        "regex": "^I[A-Z]",
        "match": false
      }
    }
  ]
}

TypeScript-Specific Best Practices

Use Interfaces for Object Shapes

Define the shape of objects using interfaces.

interface User {
  id: number;
  name: string;
  email: string;
}

Use Enums for Constant Values

Use enums to define a set of named constants.

enum UserRole {
  Admin,
  Editor,
  Viewer
}

Type Guards

Use type guards to narrow down types.

function isUser(obj: any): obj is User {
  return obj && typeof obj.id === 'number' && typeof obj.name === 'string';
}

Generics

Use generics to create reusable components.

function identity<T>(arg: T): T {
  return arg;
}

Advanced TypeScript Features

Utility Types

Utilize built-in utility types like Partial, Readonly, Pick, and Omit.

type PartialUser = Partial<User>;
type ReadonlyUser = Readonly<User>;

Conditional Types

Use conditional types to define types based on conditions.

type MessageOf<T> = T extends { message: infer MessageType } ? MessageType : never;

Mapped Types

Use mapped types to create new types based on existing types.

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

This structured wiki entry should help your development team understand and apply the TypeScript rules effectively in your Angular project.

Resources

⚠️ **GitHub.com Fallback** ⚠️