1. Introduction: The Importance of ESLint in Collaborative Angular Projects

In the world of software development, code consistency and quality are fundamental pillars for the success of any project, especially when working in a collaborative environment. This is where tools like ESLint come into play, becoming indispensable allies for Angular developers. ESLint is a static code analyzer for JavaScript that identifies problematic patterns in the code and helps developers write cleaner code and avoid potential errors through the application of configurable rules.

The usefulness of ESLint lies in its ability to examine source code without executing it, allowing problems to be detected in the early stages of development. This not only helps reduce the number of errors that reach production but also encourages the adoption of uniform coding standards across the team. By defining and following a consistent set of linting rules, code readability and maintainability are significantly improved, facilitating collaboration and reducing the possibility of different coding styles causing confusion or conflicts. The widespread adoption of ESLint in the JavaScript ecosystem, evidenced by its over 43 million weekly downloads, underscores its reliability and strong community support, ensuring a wealth of available resources and solutions.

2. Installing ESLint in an Angular Project

If your Angular project doesn’t come with ESLint preconfigured (which is common in versions of Angular 12 and later), installation is a straightforward process thanks to the Angular command-line tool (Angular CLI). The @angular-eslint/schematics package facilitates the automated setup of ESLint in Angular projects.

To start, open the terminal at the root of your Angular project and run the following command:

ng add @angular-eslint/schematics

This command downloads and installs the @angular-eslint/schematics package and performs the necessary configurations to integrate ESLint into your Angular project. Internally, this schematic automates several important steps. First, it modifies the package.json file to include ESLint dependencies and related plugins for TypeScript and Angular, as well as adding a script in the “scripts” section to facilitate running the linter. Then, it updates the angular.json file to register an ESLint builder. This builder allows running ESLint via Angular CLI commands, like ng lint. Finally, it creates or modifies the .eslintrc.json configuration file in the project root, where the linting rules will be defined. Using Angular Schematics significantly simplifies this process, abstracting the need to manually install dependencies and configure multiple files, which saves time and reduces the potential for errors.

3. Basic Configuration of the .eslintrc.json File

Once ESLint is installed in your Angular project, the key file for its configuration is .eslintrc.json, located in the project root. This file defines the rules that ESLint will use to analyze your code. Below is an example of a basic configuration for an Angular project:

{
  "root": true,
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended"
      ],
      "rules": {
        "@typescript-eslint/no-unused-vars": "warn",
        "no-console": "error"
      }
    }
  ]
}

Let’s analyze each section of this file:

  • root: true: This line indicates that this is the root configuration file for ESLint for the project. When ESLint analyzes files in the project, it will start looking for an .eslintrc.json file in the current file’s directory and continue up the directory hierarchy until it finds a file with root: true or reaches the file system root. This ensures that the configuration defined in this file applies to the entire project and prevents configurations from parent directories from being accidentally used.
  • overrides: […]: This section allows defining specific configurations for certain groups of files using glob patterns. It’s useful when different rules need to be applied to different types of files within the same project.
  • files: [“*.ts”]: Within the overrides section, this property specifies which files the configuration defined in this block will apply to. In this case, the *.ts pattern indicates that the rules within this override will only apply to files with the .ts extension, which are the TypeScript code files in an Angular project.
  • extends: […]: This property is fundamental, as it specifies one or more predefined configurations from which the current configuration inherits. This allows leveraging recommended rule sets without having to define them all from scratch. In the example, three configurations are extended:
    • eslint:recommended: This is a set of basic rules recommended by the ESLint team that cover many common potential errors and bad practices in JavaScript.
    • plugin:@typescript-eslint/recommended: This configuration comes from the @typescript-eslint/eslint-plugin plugin and enables a set of specific rules for TypeScript, recommended by the TypeScript development team. For ESLint to understand TypeScript syntax, it’s necessary to use the @typescript-eslint/parser parser, which is usually installed along with this plugin.
    • plugin:@angular-eslint/recommended: This configuration is provided by the @angular-eslint/eslint-plugin plugin and includes specific rules for Angular projects, helping to ensure compliance with the framework’s conventions and best practices. Extending predefined configurations provides a solid foundation of linting rules based on established best practices, saving developers from having to define every rule from the beginning.
  • rules: This section allows customizing the behavior of the extended rules or defining additional project-specific rules. Rules are defined as key-value pairs, where the key is the rule name and the value is the severity level or an additional configuration for that rule. In the example, two rules are defined:
    • @typescript-eslint/no-unused-vars: “warn”: This rule, provided by the TypeScript plugin, warns about declared variables in the code that are not used. The warn severity level indicates that if an unused variable is found, ESLint will show a warning, but the linting process will not fail.
    • no-console: “error”: This rule, provided by ESLint, marks the use of the console.log() function (and other related console API functions) in the code as an error. The error severity level means that if a call to console.log() is found, the linting process will fail, which can be useful to prevent code with undeleted logs from being deployed to production.

The ability to configure rule severity levels (like “warn”, “error”, “off”) allows development teams to gradually apply coding standards and prioritize fixing critical issues over less severe stylistic concerns.

4. Advanced Configuration and Recommended Rules

The basic configuration of the .eslintrc.json file provides an excellent foundation for most Angular projects. However, ESLint offers great flexibility to further customize rules according to the specific needs of your team and project.

In the rules section of the .eslintrc.json file, you can add new rules, modify the severity of extended rules, or even disable them completely. Additionally, the ESLint community has developed a wide variety of plugins that extend ESLint‘s base functionality, adding specific rules for different libraries, frameworks, or coding patterns.

Below are some examples of advanced rules often recommended for Angular projects:

  • Avoid using “any”: The @typescript-eslint/no-explicit-any: “error” rule from the TypeScript plugin is crucial for fully leveraging the benefits of static typing offered by TypeScript. Setting this rule to “error” forces developers to be explicit with types and avoids using the “any” type when not strictly necessary. Excessive use of “any” can weaken compile-time type checking, potentially leading to runtime errors that TypeScript is designed to prevent.
  • Require strict null checks: The @typescript-eslint/strict-boolean-expressions: “warn” rule, also from the TypeScript plugin, helps prevent errors by ensuring that boolean expressions only use explicit boolean values. This avoids implicit conversions that could lead to unexpected behavior, especially when working with values that might be null or undefined. The “warn” level suggests paying attention to these cases, although they are not considered critical errors that halt development immediately.
  • Enforce naming conventions: The @typescript-eslint/eslint-plugin plugin provides the @typescript-eslint/naming-convention rule, which allows defining specific naming patterns for different types of identifiers, such as interfaces, classes, variables, methods, etc. Configuring these rules helps maintain consistency in code naming, significantly improving readability and making the project easier for all team members to understand. For example, rules can be defined so that interfaces start with an uppercase I (e.g., interface IUserService), methods use camelCase, and constants are in UPPER_SNAKE_CASE.
  • Linting HTML templates: To ensure code quality not only in TypeScript files but also in Angular‘s HTML templates, the @angular-eslint/eslint-plugin-template plugin can be used. This plugin allows ESLint to analyze and apply rules to files with the .html extension. To enable it, you first need to install the plugin:
npm install --save-dev @angular-eslint/eslint-plugin-template

Then, you need to configure it in your .eslintrc.json file. In the plugins section, add “@angular-eslint/template”. Additionally, in the overrides section, add a specific configuration for *.html files:

{
  "root": true,
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended"
      ],
      "rules": {
        "@typescript-eslint/no-unused-vars": "warn",
        "no-console": "error"
      }
    },
    {
      "files": ["*.html"],
      "extends": ["plugin:@angular-eslint/template/recommended"]
    }
  ]
}

Extending ESLint to analyze Angular‘s HTML templates ensures consistency and adherence to best practices not only in the TypeScript code but also in the presentation layer, leading to a more robust and maintainable application.

5. Integration with Prettier for Automatic Formatting

While ESLint focuses on semantic quality and enforcing style rules, Prettier is a tool that handles automatic code formatting to ensure a consistent style throughout the project. It’s important to understand the fundamental difference between them: ESLint is a linter that identifies problems, whereas Prettier is a formatter that corrects code style.

To integrate Prettier with ESLint in an Angular project, you need to install two additional packages as development dependencies: eslint-config-prettier and eslint-plugin-prettier.

Run the following commands in the terminal:

npm install --save-dev eslint-config-prettier eslint-plugin-prettier
  • eslint-config-prettier: This package disables all ESLint formatting rules that might conflict with Prettier.
  • eslint-plugin-prettier: This plugin allows running Prettier as an ESLint rule, showing formatting issues as ESLint errors.

Once these packages are installed, you need to modify your .eslintrc.json file to integrate them. In the extends section within the override for TypeScript files, add “plugin:prettier/recommended” to the end of the array. It’s crucial that this line is last, as the order in the extends array matters; later configurations take precedence over earlier ones.

The .eslintrc.json file with Prettier integrated should look like this:

{
  "root": true,
  "overrides": [
    {
      "files": ["*.ts"],
      "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:@angular-eslint/recommended",
        "plugin:prettier/recommended" // Añadir esta línea
      ],
      "rules": {
        "@typescript-eslint/no-unused-vars": "warn",
        "no-console": "error"
      }
    }
  ]
}

By placing “plugin:prettier/recommended” at the end of the extends array, it ensures that Prettier‘s formatting rules have the lowest priority and do not conflict with other ESLint configurations. This allows ESLint to handle code quality and Prettier to handle formatting, working together harmoniously.

FeatureESLintPrettier
TypeLinter (static code analyzer)Code formatter
FocusIdentifies problematic patterns, style errors, and best practicesEnsures a consistent and uniform code style across the project
ConfigurationHighly configurable, allows customizing specific rulesOpinionated with limited configuration options
GoalSemantic quality and code correctnessVisual presentation and code consistency
OutputReports errors and warnings about the codeReformats the code to apply a consistent style

6. Conclusion: Fostering Clean and Maintainable Code in Angular Teams

Implementing ESLint and configuring it correctly in Angular projects is an invaluable investment for any development team. Adopting these practices promotes writing cleaner, more consistent, and maintainable code throughout the project lifecycle. The ability to detect errors early, apply uniform coding standards, and automate code formatting facilitates collaboration, reduces friction among team members, and ultimately leads to the creation of higher-quality Angular applications.

For those who wish to delve deeper into ESLint configuration and explore the numerous available options and rules, consulting the official ESLint documentation at eslint.org is recommended. Additionally, specific plugins for Angular, such as @angular-eslint/eslint-plugin and @angular-eslint/eslint-plugin-template, offer a wide range of rules designed to ensure compliance with the framework’s best practices. Exploring these resources will allow developers to further customize their linting setup and adapt it to the particular needs of their projects and teams.

If you’d like to complement your setup with more in-depth guides on Husky and Prettier, check out these articles: