Get Started
- CodeAnt AI
- Control Center
- Pull Request Review
- IDE
- Compliance
- Anti-Patterns
- Code Governance
- Infrastructure Security Database
- Application Security Database
Angular
Classes decorated with @Component must have suffix “Component” (or custom) in their name. See more at https://angular.io/styleguide#style-02-03
import { Component } from '@angular/core';
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.css']
})
export class Alert {
// Component logic goes here
}
- Ensures consistency in the naming of component classes, which helps in quickly identifying component classes within a project and improves readability for new developers joining the project.
- Aligns with Angular’s style guide and best practices, which recommend a naming convention that includes a suffix indicating the type of class (e.g., Component), thus preventing confusion with services, modules, or other Angular constructs.
- Enhances maintainability of the codebase by enforcing a clear and predictable naming structure which makes it easier for developers to navigate and refactor the code when necessary.
- Helps in avoiding naming conflicts and clarifies the purpose of the class, ensuring that component classes are easily distinguishable from other classes that might not be components, thus reducing potential errors during development.
Enforces a maximum number of lines in inline template, styles and animations. See more at https://angular.io/guide/styleguide#style-05-04
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
template: `
<div>
<h1>Title</h1>
<p>Some initial content...</p>
<!-- Imagine many more lines here, making the template excessively long -->
<p>More content in the middle...</p>
<!-- More lines continuing the overlong template -->
<p>Even more content towards the end...</p>
</div>
`,
styles: [
`
div {
display: flex;
flex-direction: column;
}
h1 {
color: blue;
}
p {
font-size: 16px;
}
/* And possibly more overly verbose styling here */
`
]
})
export class ExampleComponent {}
- Enforces separation of concerns by encouraging developers to use external files for templates and styles rather than inline code, which aligns with Angular’s best practices as per the Angular Style Guide. This separation makes the component class cleaner and focused on its primary purpose: handling business logic.
- Improves readability and maintainability of component code by reducing clutter. Large inline templates or styles within component decorators can make the code hard to navigate and understand, especially for new developers or when returning to the component after some time.
- Enhances scalability and reusability of styles and templates. By promoting the use of separate files for templates and styles, this rule indirectly encourages the development of more modular and reusable components. External stylesheets and templates can be more easily modified, shared, and reused across different components.
- Simplifies collaboration and version control. Having templates and styles in separate files makes it easier for multiple developers to work on different aspects of a component simultaneously without causing merge conflicts. It also improves the clarity of code changes in version control systems, making it easier to track changes to specific parts of the component’s UI or styling.
Component selectors should follow given naming rules. See more at https://angular.io/guide/styleguide#style-02-07, https://angular.io/guide/styleguide#style-05-02 and https://angular.io/guide/styleguide#style-05-03.
import { Component } from '@angular/core';
@Component({
selector: 'MyComponent', // This is bad because the selector does not follow naming conventions
template: `<div>My bad component</div>`
})
export class MyComponent {}
- This rule enforces a consistent naming convention for Angular component selectors which aligns with Angular’s recommended style guides. Adhering to these conventions makes the code more readable and organized, particularly in larger projects or teams.
- By specifying a prefix (e.g., ‘app-’) for component selectors, this rule helps in avoiding naming collisions with HTML elements and with selectors from third-party libraries, enhancing the maintainability of the codebase.
- It promotes the use of kebab-case for component selectors, which is a widely accepted convention for naming CSS classes and HTML attributes. This consistency between selectors and CSS classes improves the coherence of the code, making it easier to understand and debug.
- Implementing this rule aids in automated code linting and refactoring. As the rule clearly defines the correct format for selectors, tools can automatically identify and even fix deviations from the standard, streamlining the development process and reducing the chances of human error.
Ensures that classes use contextual decorators in its body
// Missing @Injectable decorator for a service class
class DataService {
constructor(private http: HttpClient) {}
fetchData() {
// Implementation to fetch data
}
}
-
Ensures that Angular classes such as services are correctly annotated with the relevant decorator like
@Injectable()
, signifying that they can be injected with dependencies, which is key for Angular’s dependency injection mechanism to work properly. This also ensures that the Angular application follows best practices in terms of service creation and management. -
Increases code readability and maintainability by making it explicit which classes are intended to be used as providers in Angular’s dependency injection system. When a class is decorated with
@Injectable()
, it signals to developers and the framework that this class follows the Angular pattern for services, making it easier to understand the architecture and flow of the application. -
Helps prevent runtime errors that occur when trying to inject dependencies into a class that has not been decorated with
@Injectable()
. The Angular framework relies on decorators to identify and inject dependencies; without the appropriate decorator, the framework cannot properly construct an instance of the class, leading to difficult-to-trace bugs. -
Facilitates better tooling support and early detection of potential issues during development. By enforcing the use of contextual decorators through this ESLint rule, developers can catch and fix incorrect or missing decorator usage before the code is executed. This preemptive correction helps in reducing debugging time and effort, especially in large projects where manual verification of each service or provider might be impractical.
Ensures that lifecycle methods are used in a correct context
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor() {}
ngOnInit() {
console.log('Service initialized');
}
}
- Ensures Angular lifecycle hooks, like
ngOnInit
, are not mistakenly used within services (@Injectable
), where they have no effect and can mislead developers about the service initialization process. - Promotes best practices by guiding developers to initialize services in the constructor, which is the appropriate lifecycle phase for service setup, thus adhering to Angular’s design principles.
- Helps in maintaining consistency across the codebase by preventing the misuse of component-specific lifecycle methods in services, making the code easier to understand and reducing potential bugs from improper lifecycle hook usage.
- Increases code readability and maintainability by ensuring lifecycle methods are only used where they are intended to be, thereby preventing future developers from spending time debugging issues related to lifecycle hooks mistakenly placed in services.
Classes decorated with @Directive must have suffix “Directive” (or custom) in their name. See more at https://angular.io/styleguide#style-02-03
import { Directive } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class Highlight {
// Some logic here
}
- Ensures consistent naming for classes decorated with
@Directive
, making the codebase easier to read and maintain by clearly indicating the purpose and nature of each class. - Facilitates better searchability and organization within large projects by having a uniform suffix (“Directive”) for all directive classes, thus quickly distinguishing them from services, components, and modules.
- Prevents naming collisions and confusion between regular classes and directive classes, especially when they serve related but distinct roles within the application, enhancing code clarity.
- Adheres to Angular’s official style guide, fostering best practices and standard conventions across Angular development communities for improved code quality and easier collaboration.
Directive selectors should follow given naming rules. See more at https://angular.io/guide/styleguide#style-02-06 and https://angular.io/guide/styleguide#style-02-08.
import { Directive } from '@angular/core';
// Violates the directive-selector rule by not using a specific prefix and using camelCase.
@Directive({
selector: 'myDirective',
})
export class MyDirective { }
- Enforcing a specific naming convention for directive selectors, such as requiring a prefix and kebab-case, ensures consistency across the codebase. This makes it easier for developers to understand and identify directive selectors quickly within the application.
- The rule encourages the use of application-specific prefixes for directive selectors, which helps to avoid conflicts with naming conventions of third-party libraries and ensures that directives are uniquely identifiable as belonging to the application.
- By aligning with the Angular style guide recommendations (as referenced in the description links), this linting rule helps in maintaining industry-standard practices within Angular projects. This standardization is beneficial for developer onboarding and collaboration, as it reduces the learning curve for new team members familiar with Angular conventions.
- The provided example of a ‘bad’ versus ‘fix’ scenario illustrates how adherence to this rule not only improves readability but also enhances the semantic understanding of the template code. This assists in debugging and maintaining the code, as directive selectors clearly convey their purpose and ownership within the application’s architecture.
Angular Lifecycle methods should not be async. Angular does not wait for async lifecycle but the code incorrectly suggests it does.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
async ngOnInit() {
await this.loadData();
}
async loadData() {
// Imagine this method fetches data asynchronously
}
}
-
This ESLint rule prevents the misleading use of
async
in Angular lifecycle methods such asngOnInit
, signaling to developers that Angular lifecycle methods don’t support the handling of asynchronous operations in the way they might expect. Usingasync
suggests Angular waits for the operation to complete, which it doesn’t, possibly leading to race conditions or uninitialized data. -
The rule enforces patterns that lead to better error handling. By removing
async
from the lifecycle method and using promises with.then()
and.catch()
, developers are encouraged to explicitly handle success and failure cases of asynchronous operations, improving the robustness of the application. -
This rule aids in maintaining consistency across the codebase by enforcing a pattern where asynchronous operations inside lifecycle methods are handled in a similar manner. This consistency helps new developers understand the code faster by setting a clear expectation of how asynchronous operations should be managed within lifecycle hooks.
-
Implementing this rule can improve the performance perception of Angular applications. By correctly handling asynchronous operations without blocking lifecycle methods, the application can render its UI components faster, and then update them as data loads, leading to a smoother user experience.
The @Attribute decorator is used to obtain a single value for an attribute. This is a much less common use-case than getting a stream of values (using @Input), so often the @Attribute decorator is mistakenly used when @Input was what was intended. This rule disallows usage of @Attribute decorator altogether in order to prevent these mistakes.
import { Component, Attribute } from '@angular/core';
@Component({
selector: 'app-example',
template: `<p>{{ attributeValue }}</p>`,
})
export class ExampleComponent {
constructor(@Attribute('attributeValue') public attributeValue: string) {}
}
- Ensures developers use the more frequently applicable
@Input
decorator for property binding in Angular components instead of the less commonly needed@Attribute
decorator, improving code consistency and understanding among team members. - Prevents the incorrect usage of the
@Attribute
decorator which is meant for fetching the initial value of a host element attribute, not for dynamic two-way data binding which is more often the requirement in modern Angular applications. - Promotes better practice by encouraging the use of
@Input
, which is designed for component input properties and supports dynamic values via data binding, aligning with Angular’s reactive programming model. - Avoids potential confusion and bugs by eliminating the misuse of
@Attribute
for scenarios where developers intend to have dynamic data binding with parent components, ensuring the components are correctly responsive to data changes.
Ensures that directives not implement conflicting lifecycle interfaces.
import { Component, OnInit, OnDestroy, OnChanges } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit, OnDestroy, OnChanges {
constructor() { }
ngOnInit() {
console.log('Component initialized');
}
ngOnChanges() {
console.log('Component properties changed');
}
ngOnDestroy() {
console.log('Component destroyed');
}
}
- This rule prevents the implementation of conflicting lifecycle hooks in Angular components or directives, which can lead to unexpected behavior or bugs in the application. For instance, implementing both
OnInit
andOnDestroy
withoutOnChanges
can indicate a misunderstanding of when these hooks are supposed to be used. - It promotes best practices by encouraging the developer to understand and correctly use Angular’s lifecycle interfaces. Ensuring that only compatible or non-conflicting lifecycle hooks are implemented together helps maintain the component’s logic clear and predictable.
- The rule aids in code readability and maintenance. By avoiding the implementation of unnecessary or conflicting lifecycle hooks, the component’s purpose and behavior become more straightforward to other developers who might work on the same codebase.
- It can assist in performance optimization. Implementing unnecessary lifecycle hooks can lead to additional checks and executions that might not be needed for the component’s intended functionality, potentially impacting the application’s performance negatively.
Disallows declaring empty lifecycle methods
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit(): void {
// Empty ngOnInit method
}
}
- Prevents the inclusion of lifecycle methods that do not implement any logic, which can help in maintaining a cleaner and more readable codebase by eliminating unnecessary code.
- Helps in enforcing best coding practices within an Angular-based project by encouraging developers to only implement lifecycle methods when there is a need to hook into specific points of the component lifecycle.
- Reduces the potential for confusion among team members or new developers working on the project by avoiding empty method implementations that may suggest an unfinished or missing implementation.
- Enhances performance optimization opportunities by eliminating empty methods that Angular would otherwise needlessly call during the lifecycle of a component, thereby slightly reducing the overhead in the component initialization process.
Disallows usage of forwardRef
references for DI
import { Component, Inject, forwardRef } from '@angular/core';
import { ParentComponent } from './parent.component';
@Component({
selector: 'app-child',
template: `<div>Child component content</div>`,
})
export class ChildComponent {
constructor(@Inject(forwardRef(() => ParentComponent)) private parent: ParentComponent) {}
}
- This rule prevents complex dependencies within Angular applications by disallowing the use of
forwardRef
in dependency injections. The usage offorwardRef
can lead to hard-to-trace dependencies and might complicate the DI framework’s ability to statically analyze and detect services, potentially leading to runtime errors or complicated debugging sessions. - Implementing this rule encourages developers to design their component and service relationships more straightforwardly, promoting better architecture. Instead of relying on
forwardRef
to circumvent circular dependencies, developers are pushed to reconsider their application’s structure, possibly refactoring their code to avoid such circular references in the first place. - By discouraging the use of
forwardRef
, this rule indirectly enhances application performance. SinceforwardRef
adds an extra layer of complexity to the DI mechanism, removing its usage can lead to a more optimized dependency resolution process at runtime, resulting in faster application startup times and potentially better runtime performance. - Compliance with this rule can improve code readability and maintainability. When
forwardRef
is used, it can be less clear why a certain service is injected in a particular way, especially to those new to the codebase or Angular. Enforcing this rule means that developers need to find alternative, and often more straightforward, methods of dependency injection, which can make the code easier to understand and maintain.
Disallows usage of the host
metadata property. See more at https://angular.io/styleguide#style-06-03
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css'],
host: {'(click)': 'onClick($event)'}
})
export class ExampleComponent {
onClick(event: Event) {
// Handle click event
}
}
- Encourages best practices in Angular development by advising against the use of the
host
metadata property within@Component
decorators, aligning with Angular style guide recommendations. - Promotes a more declarative approach by suggesting the use of
@HostListener
for handling DOM events, making the component class cleaner and the event handling logic more transparent. - Enhances code maintainability and readability by discouraging the mixing of component metadata with event handling logic, thus separating concerns more effectively.
- Aids in preventing potential issues related to specificity and override problems that can arise when using the
host
metadata property, leading to a more stable Angular application structure.
Ensures that input bindings, including aliases, are not named or prefixed by the configured disallowed prefixes
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-example',
template: `...`,
})
export class ExampleComponent {
@Input() isDisabled: boolean; // Bad because of the 'is' prefix
}
-
This rule helps in maintaining a consistent naming convention for input properties in Angular components, avoiding confusion regarding whether the property name implies a method/function or a boolean variable. By discouraging prefixes like ‘is’, ‘should’, etc., it ensures property names are understood as state descriptions rather than actions.
-
It enhances code readability by eliminating unnecessary prefixes in input properties. By encouraging concise and meaningful names, developers can quickly understand the component’s API and its intended use, leading to more intuitive codebases.
-
The rule assists in enforcing best practices for naming conventions within Angular projects. Adhering to such standards makes the code more approachable for new team members and maintains uniformity across different components, making the project easier to navigate and maintain.
-
By preventing the use of specific prefixes in input properties, the rule indirectly promotes the use of type annotations and TypeScript’s strong typing features. This helps in catching potential bugs at compile time rather than at runtime, improving the overall quality and reliability of the application.
Ensures that input bindings are not aliased
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-user',
template: `<h1>Hello, {{person}}</h1>`,
})
export class UserComponent {
@Input('person') user: string = '';
}
-
The rule
'angular/no-input-rename'
discourages the practice of aliasing input bindings, promoting direct and clear communication between parent and child components in Angular applications. This ensures a more readable and maintainable codebase, as developers can easily understand and trace property bindings without the need to decipher aliased names. -
By enforcing no input renaming, the rule helps in maintaining consistency across the codebase. When developers adhere to this rule, all input bindings follow a uniform pattern, reducing the cognitive load required to understand different components’ APIs. This consistency is crucial for larger teams or projects, where multiple developers contribute code.
-
The rule detects potentially confusing patterns where an input property is given an alias. Such patterns could lead to misunderstanding among developers about what property a parent component should provide or which property a child component is expecting. By keeping the property name the same in both the child and parent components, it becomes straightforward to track and debug data flow through the application.
-
Adhering to this rule can also positively impact the documentation and tooling around an Angular application. Tools that generate documentation based on the component’s code or provide IDE support for auto-completion and navigation perform better when the input bindings are not aliased. This leads to improved developer experience, as the tooling can accurately represent component interfaces and relationships.
Disallows usage of the inputs
metadata property. See more at https://angular.io/styleguide#style-05-12
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css'],
inputs: ['input1', 'input2'] // This is the discouraged practice
})
export class ExampleComponent {
input1: string;
input2: string;
}
-
The rule enforces the best practice recommended by the Angular style guide (Style 05-12), which advocates for using the
@Input()
decorator over theinputs
array in the@Component
decorator. This makes the code more readable and the bindings between parent and child components clear. -
By disallowing the
inputs
metadata property, the rule encourages developers to declare inputs explicitly within the component class, which can enhance type safety by allowing TypeScript to check and enforce appropriate types for the properties. -
The rule helps maintain consistency across the codebase by ensuring all components follow the same method for declaring inputs. This consistency improves readability and makes the code easier to understand for new developers joining the project.
-
It potentially prevents errors related to the improper use of the
inputs
metadata property. Explicitly defining inputs with the@Input()
decorator makes it less likely that inputs will be omitted or misconfigured within the component metadata, thereby reducing debugging time and increasing the application’s reliability.
Disallows explicit calls to lifecycle methods
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
constructor() { }
ngOnInit() {
console.log('OnInit has been called');
}
someMethod() {
// Explicit call to the lifecycle method which is bad practice
this.ngOnInit();
}
}
-
Prevents the potential risk of calling Angular lifecycle methods multiple times unintentionally which could lead to unexpected behavior or side effects in the application, as lifecycle methods are managed by Angular’s change detection mechanism and not designed to be invoked manually.
-
Ensures better code maintainability and readability by encouraging developers to isolate reusable code into separate methods rather than calling lifecycle methods directly, which can confuse new developers or lead to spaghetti code over time.
-
Enhances code modularity and reuse by promoting the extraction of common logic from lifecycle methods into standalone functions that can be called both from the lifecycle method and elsewhere, thus adhering to the DRY (Don’t Repeat Yourself) principle.
-
Increases the robustness of Angular applications by helping to enforce best practices around lifecycle method usage, as directly invoking these methods can bypass Angular’s optimizations and error handling strategies, potentially leading to performance issues and harder-to-debug errors.
Ensures that output bindings, including aliases, are not named as standard DOM events
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-example',
template: `<button (click)="onClick()">Click me!</button>`
})
export class ExampleComponent {
@Output() click = new EventEmitter<void>(); // Bad practice
onClick() {
this.click.emit();
}
}
- This rule prevents confusion between Angular component output bindings and standard DOM event names, ensuring clear differentiation in the codebase. Specifically, using an output binding named ‘click’ can lead to confusion as it seems to directly handle native click events, whereas it’s actually an Angular event emitter.
- Enforcing this rule promotes better code readability and maintainability by making it explicit that an output binding is a custom event rather than a native DOM event. This distinction is crucial for developers who are new to the codebase or those working in large, complex projects where clarity is key.
- It helps avoid potential bugs related to event handling. For example, if a developer mistakenly assumes that an output named ‘click’ directly handles native click events, they might not implement necessary event handling logic, leading to unexpected behavior in the application.
- Adhering to this rule can simplify debugging and testing processes. By clearly naming output bindings to not mimic native event names, it becomes easier to trace through code and understand event flows, particularly in complex components with multiple outputs and event handlers.
Ensures that output bindings, including aliases, are not named “on”, nor prefixed with it. See more at https://angular.io/guide/styleguide#style-05-16
import { Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-example',
})
export class ExampleComponent {
// This output property is not following the guideline
@Output() onStatusChange = new EventEmitter<boolean>();
}
- This rule helps ensure that Angular output bindings follow the naming conventions recommended in the Angular style guide, making the codebase consistent with best practices and easier for team members to understand and maintain.
- Preventing the use of “on” or “on” prefixes in output bindings reduces confusion with event listeners in templates, where an “on” prefix typically indicates an event handler rather than an output property, leading to clearer separation of component interaction patterns.
- Enforcing this rule can improve code readability by making output bindings’ intent clearer without implying that they directly handle events. Instead, it suggests that they emit events, which can be listened to by parent components or directives, contributing to a more intuitive component API.
- Adhering to this guideline helps in avoiding naming conflicts between internal component events and native DOM events, potentially reducing bugs related to event handling and making the components more stable and predictable in their behavior.
Ensures that output bindings are not aliased
import { Output, EventEmitter } from '@angular/core';
class SomeComponent {
// Output property 'update' is aliased to 'change', which violates the 'angular/no-output-rename' rule
@Output('change') update = new EventEmitter<string>();
}
-
Encourages consistency in naming across the application by ensuring that output properties in Angular components use their original names, making the codebase more predictable and easier to navigate for developers familiar and new to the project.
-
Helps prevent confusion for developers who use or maintain the component, as aliasing can obscure the intention or functionality of an output event, especially for those not involved in its initial development or when returning to the code after some time.
-
Enhances readability and reduces the cognitive load required to understand the component’s API by removing unnecessary indirection. When outputs are not aliased, their intended use and functionality are clearer, making the component’s interface more straightforward.
-
Improves the maintainability of the code by adhering to Angular’s best practices, which advocate for clear and semantic naming. This can lead to fewer bugs related to event handling because developers are less likely to misunderstand or misuse output events.
Disallows usage of the outputs
metadata property. See more at https://angular.io/styleguide#style-05-12
import { Component, EventEmitter } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
outputs: ['changeEvent: change'] // This usage is discouraged
})
export class ExampleComponent {
changeEvent = new EventEmitter<any>();
triggerChange() {
this.changeEvent.emit('someValue');
}
}
-
Enforces a consistent decoration style for outputs in Angular components, which improves readability and maintainability of the code. By using the
@Output()
decorator directly on the property, it is immediately clear that the property is intended to be an output. -
Aligns with Angular’s style guide recommendation (as per the link provided in the description), which advocates for using decorators like
@Output()
over theoutputs
array in@Component
metadata. Following these best practices helps in keeping the code standardized across different projects and developers. -
Reduces the risk of typos or errors in the
outputs
metadata property, which might be less intuitive and error-prone, especially for developers new to Angular or working on large projects. Directly decorating the properties with@Output()
makes it easier to identify outputs and their corresponding events. -
Enhances tooling support and potential for static analysis, as modern IDEs and Angular tooling can more easily identify outputs decorated with
@Output()
, allowing for better autocomplete, refactoring capabilities, and error detection. This can lead to a more efficient development process and fewer runtime errors.
Disallows the declaration of impure pipes
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'myCustomPipe',
pure: false // This is what makes the pipe impure
})
export class MyCustomPipe implements PipeTransform {
transform(value: any, ...args: any[]): any {
// transformation logic here
return modifiedValue;
}
}
- This rule helps in ensuring that Angular pipes are used in a performance-optimized manner. Impure pipes are called on every change detection cycle, which can lead to significant performance issues, especially in complex applications with a large number of bindings or heavy computations.
- By disallowing impure pipes, developers are encouraged to design their applications to use data transformations that are deterministic and side-effect free. This aligns with functional programming principles, making the data flow through the application easier to understand and debug.
- It encourages the use of pure pipes where transformations only depend on the input values. This makes it easier to predict the outcome of a transformation, as pure pipes guarantee the same output for the same input, improving the overall reliability of the application.
- Enforcing the use of pure pipes, as this rule does, promotes better state management practices within Angular applications. Since pure pipes react only to changes in their input, it encourages developers to architect their application’s state in an immutable fashion, leading to applications that are easier to reason about and less prone to state-related bugs.
Disallows usage of the queries
metadata property. See more at https://angular.io/styleguide#style-05-12.
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css'],
queries: {
contentChildren: new ContentChildren(MyDirective),
viewChildren: new ViewChildren(MyComponent)
}
})
export class ExampleComponent {
}
-
Encourages best practices as outlined in the Angular style guide, specifically rule 05-12, which helps maintain consistency across Angular projects by advising against the use of the
queries
metadata property in component decorators. -
Promotes better code readability and maintainability by moving child queries closer to their relevant contexts. Using
@ContentChildren
and@ViewChildren
decorators directly in class definitions makes it easier for developers to identify and understand component relationships and dependencies. -
Facilitates easier debugging and refactoring by having query declarations within the class body. This structural convention aids in pinpointing query-related issues faster, as opposed to sifting through decorator metadata, thus speeding up the development process.
-
Aligns with Angular’s shift towards a more declarative approach of handling queries by using decorators. This not only makes the code more expressive but also leverages Angular’s dependency injection system more effectively, allowing for improved performance optimizations and more intuitive API usage.
Enforce consistent prefix for pipes.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'dateFormat'
})
export class DateFormatPipe implements PipeTransform {
transform(value: Date | string, ...args: any[]): string {
// Implementation for transforming the input date or string to a desired format
return ''; // Simplified for the example
}
}
- The rule ensures that all Angular pipes have a consistent prefix, which aids in quickly identifying pipe-related files or classes within a large project, improving readability and maintainability.
- By enforcing a specific prefix for pipes, it helps in avoiding naming collisions with pipes defined in third-party libraries or Angular’s built-in pipes, reducing potential runtime errors and debugging time.
- It promotes best coding practices within team environments, ensuring that all developers follow a standardized naming convention for pipes, leading to more cohesive and understandable codebases.
- Implementing this rule can aid in documentation and tooling, as tools that generate documentation or perform static code analysis can more easily identify and categorize pipes, improving the overall development workflow.
Ensures component’s changeDetection
is set to ChangeDetectionStrategy.OnPush
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {
// component logic
}
-
This ESLint rule promotes the use of
ChangeDetectionStrategy.OnPush
in Angular components, which ensures that change detection runs only when the reference to an input property changes. This can lead to significant performance improvements in applications, especially those with complex component trees, by reducing the frequency of change detection checks. -
Enforcing this rule helps in establishing a consistent coding practice across the project, making the components more predictable in behavior. Since all components would follow the
OnPush
change detection strategy, developers can easily understand and manage the state and change detection flow within the application. -
The rule can help in catching potential bugs early in the development process. Since
OnPush
change detection requires explicit triggering for changes to be reflected in the view, developers are less likely to inadvertently rely on Angular’s default change detection to update the view when data changes, encouraging better data management practices. -
Applying this rule can lead to better performance optimization by making developers more mindful of how and when change detection occurs in their applications. With
OnPush
, developers need to explicitly mark components for check or update input properties immutably, leading to less unnecessary checks and updates, and ultimately a smoother user experience.
Prefer to declare @Output
as readonly
since they are not supposed to be reassigned
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-example',
template: '<p>Bad Output Example</p>',
})
export class ExampleComponent {
@Output() badOutputExample = new EventEmitter<string>();
}
-
The rule enforces best practices in Angular applications by ensuring that
@Output
properties are declared asreadonly
. This aligns with the design principle that output properties should not be reassigned after initialization, promoting immutability and reducing potential bugs related to the unintended modification of these properties. -
By marking
@Output
properties asreadonly
, it clearly communicates the intent to other developers that these properties are meant for emitting events to parent components and should not be manipulated directly. This enhances code readability and maintainability. -
Encouraging the use of
readonly
with@Output
properties can help prevent runtime errors that might occur if an output property is accidentally reassigned. Since Angular uses these properties for output event binding, altering them can break the expected component communication flow. -
Applying this rule in an Angular project could improve performance by ensuring that the change detection mechanism of Angular does not have to account for possible changes in the
@Output
properties, as they are guaranteed not to change after their initial assignment. This can lead to more efficient detection of changes and updating of views.
Ensures component standalone
property is set to true
in the component decorator
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {
// component logic
}
- Enforcing the
standalone
property within the Angular component decorator to be set totrue
promotes the use of standalone components, which are modular and can be independently used or tested. This aligns with modern Angular practices of building scalable and maintainable applications. - By requiring the
standalone
property to be explicitly declared, this ESLint rule ensures greater consistency across the codebase. Each component’s ability to function independently or require certain dependencies is made clear, improving code readability and understanding among team members. - This rule aids in the transition towards a more decoupled architecture within Angular applications. By preferring standalone components, developers are encouraged to think about component dependencies and imports more carefully, reducing unnecessary coupling and improving the application’s overall architecture.
- The inclusion of the
standalone
property as mandated by this rule can lead to easier refactoring and testing of components. Standalone components encapsulate their dependencies, making them easier to migrate, mock, or replace during testing or when changing aspects of the application’s design or functionality.
The ./ and ../ prefix is standard syntax for relative URLs; don’t depend on Angular’s current ability to do without that prefix. See more at https://angular.io/styleguide#style-05-04
import { MyService } from 'services/my.service';
@Component({
selector: 'my-component',
templateUrl: 'my-component.html',
styleUrls: ['my-component.css']
})
export class MyComponent {
constructor(private myService: MyService) {}
}
- Ensures consistency and clarity in specifying relative paths, which helps in maintainability and readability of the code, especially in larger projects where file structure can become complex.
- Helps in preventing potential runtime errors that could arise from Angular’s resolution of paths without a leading
./
or../
, thereby improving the reliability of the application. - Aligns with Angular’s style guide and best practices, promoting coding standards that are recommended by Angular experts for scalable and efficient application development.
- Facilitates easier code refactoring and migration, as explicitly specifying relative paths makes it clearer which files are being referenced, reducing the risk of breaking imports when moving files within the project structure.
Ensures that $localize tagged messages contain helpful metadata to aid with translations.
const greeting = $localize`Hello, World!`;
-
This rule encourages the incorporation of unique identifiers within
$localize
tagged messages, which significantly enhances the traceability of texts across different languages and their translations, making it easier to manage and update translations in larger applications. -
It fosters the practice of providing additional context for translators, such as descriptions or meanings, which can be crucial for accurate translations, especially in cases where the same word might have different translations based on the context.
-
The rule helps in maintaining a standard format for localized messages in Angular-based projects, leading to consistency across the codebase. This consistency aids developers and translators to quickly understand the localization patterns employed within the application, improving the overall development and translation workflow.
-
By enforcing metadata in localizations, it indirectly facilitates better communication and collaboration between developers and translators. Translators are provided with clear, context-rich messages, thereby reducing the room for error and the back-and-forth usually required to clarify ambiguous texts, ultimately speeding up the translation process.
Ensures that lifecycle methods are declared in order of execution
import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit, OnDestroy, AfterViewInit {
// Methods are out-of-order according to lifecycle hook execution order
ngOnDestroy(): void {
// cleanup logic
}
ngOnInit(): void {
// initialization logic
}
ngAfterViewInit(): void {
// after view init logic
}
}
-
This rule ensures that Angular lifecycle methods are declared in the specific order they are executed, which aligns the source code with the natural lifecycle flow of an Angular application, making it easier to understand the component’s lifecycle at a glance.
-
Enforcing an ordered declaration of lifecycle methods reduces the cognitive load on developers who are reading or reviewing code, as they can expect a consistent ordering across different components in the application.
-
By adhering to a conventional order for lifecycle methods, it implicitly guides developers to think about and implement their component logic in alignment with the Angular framework’s lifecycle, potentially reducing logical errors related to lifecycle-dependent operations.
-
Applying this rule and its fix can lead to more maintainable code, as it standardizes the way lifecycle methods are organized within components throughout the application, facilitating easier debugging and refactoring when components evolve over time.
Ensures ASC alphabetical order for NgModule
metadata arrays for easy visual scanning
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppService } from './app.service';
import { AnotherComponent } from './another.component';
@NgModule({
declarations: [
AppComponent,
AnotherComponent // This should come before AppComponent for alphabetical order
],
imports: [
BrowserModule,
FormsModule // This should come before BrowserModule for alphabetical order
],
providers: [
AppService
],
bootstrap: [AppComponent]
})
export class AppModule { }
- Ensures consistency and readability in
NgModule
metadata arrays, which improves maintainability by making it easier to visually scan and locate specific modules, components, or services. - Helps in avoiding merge conflicts in team environments since a consistent ordering is followed, making version control systems handle changes more seamlessly.
- Enhances code quality by enforcing a standard coding practice across the project, leading to less cognitive overhead when switching between different parts of the application.
- Assists in early detection of duplicated entries within the arrays, as sorting alphabetically would place duplicates next to each other, making them more noticeable during code reviews or even at a glance.
Component selector must be declared
import { Component } from '@angular/core';
@Component({
template: `<h1>Welcome</h1>`
})
export class WelcomeComponent {
}
- Ensures consistency in defining Angular components by mandating the inclusion of a selector, which makes components easily identifiable within the module and when used in templates.
- Enhances readability and maintenance of Angular project codebases by clearly indicating that a class is meant to be used as a component and how it’s supposed to be utilized in HTML templates.
- Prevents potential runtime errors and debugging difficulties that could arise from a component being declared without a selector, ensuring that components are correctly registered and can be utilized within Angular’s rendering engine.
- Aids in enforcing project or team coding standards and conventions, particularly in larger projects or teams, by automatically checking and flagging components that do not adhere to the required structure, thus improving code quality and uniformity.
Disallows using ViewEncapsulation.None
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-no-encapsulation',
templateUrl: './no-encapsulation.component.html',
styleUrls: ['./no-encapsulation.component.css'],
encapsulation: ViewEncapsulation.None // This is what we want to avoid
})
export class NoEncapsulationComponent {
// component logic here
}
-
Ensures style encapsulation: The rule is specific to promoting the use of Angular’s default or emulated view encapsulation, which ensures that styles defined in a component’s CSS file are not applied globally. This prevents styles from unintentionally affecting other elements outside of the component.
-
Promotes best practices: By disallowing
ViewEncapsulation.None
, the rule encourages developers to follow best practices in Angular application development. Using the default view encapsulation (Emulated
) aligns with Angular’s component-based architecture, where each component should be self-contained. -
Enhances maintainability: Components designed with their own encapsulated styles are more maintainable, as changes to a component’s styles will not have side effects on other parts of the application. This rule helps in maintaining a clean separation of concerns, making it easier to debug and update styles.
-
Prevents style conflicts: In large and complex applications, global styles can easily lead to conflicts and inconsistencies in the UI. By enforcing encapsulation, this rule minimizes the risk of style conflicts and ensures a more consistent appearance across different components of the application.
Using the providedIn
property makes Injectables
tree-shakable
import { Injectable } from '@angular/core';
@Injectable()
export class UserService {
constructor() {}
}
- Ensures that Angular services are provided in the most efficient way by using the
providedIn
property, which facilitates Angular’s tree-shaking capabilities during the build process, leading to potentially smaller bundle sizes. - Helps with Angular application performance optimization by making sure that only the services that are actually used are included in the final bundle, as services not provided in any module can be easily removed by the tree-shaker.
- Promotes best practices in Angular development by encouraging developers to declare services with the
providedIn
property, aligning the codebase with the Angular team’s recommendations for service declaration. - Enhances code maintainability and readability by clearly indicating where the service is provided, making it easier for developers to understand the service’s scope and availability within the application.
Ensures that classes implement lifecycle interfaces corresponding to the declared lifecycle methods. See more at https://angular.io/styleguide#style-09-01
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {
ngOnInit() {
console.log('Component initialized');
}
}
- Ensures consistency and clarity in Angular applications by enforcing the implementation of lifecycle interfaces for components utilizing lifecycle methods, making the components’ intentions and behaviors explicitly clear.
- Prevents potential errors or unexpected behavior in Angular applications by ensuring that components correctly implement necessary lifecycle interfaces, aligning with Angular’s best practices and the framework’s lifecycle hooks expectations.
- Improves code readability and maintainability by explicitly declaring the lifecycle interfaces a component implements. This aids in quickly understanding the component’s lifecycle interactions without digging into the implementation details.
- Enhances team collaboration and code quality in large projects by establishing a standard rule across all components, ensuring that every developer follows the same practice of implementing lifecycle interfaces for lifecycle methods used, reducing the learning curve for new team members and easing code reviews.
Ensures that Pipes
implement PipeTransform
interface
import { Pipe } from '@angular/core';
@Pipe({
name: 'customPipe'
})
export class CustomPipe {
transform(value: any): any {
// Custom transformation logic
return modifiedValue;
}
}
- Ensures consistency in the application by enforcing that all Angular Pipes explicitly implement the
PipeTransform
interface, which is essential for maintaining predictable behavior of pipes across the project. - Enhances the readability and maintainability of the code by explicitly declaring the intention that a class is a Pipe and adheres to the
PipeTransform
interface, making it easier for new developers to understand the codebase. - Helps in catching typographical or logical errors at compile-time by enforcing the implementation of the
transform
method with the correct signature, reducing runtime errors due to incorrect implementations. - Promotes best practices in Angular development by ensuring that the developer adheres to the Angular framework’s guidelines, thus making the application’s code more aligned with the Angular ecosystem and potentially benefiting from optimizations or tooling support specific to Angular Pipes.