Skip to content
angular-best-practices logo

angular-best-practices

Curated Angular best practices for building performant, maintainable applications. Library-specific rules available as optional skills.

NeverSight/skills_feed0installs213stars

SKILL.md

Full skill instructions

Angular Best Practices

Curated rules for building performant, maintainable Angular applications. Library-specific rules (NgRx, SignalStore, TanStack Query) available as optional skills.

When to Use

Apply these practices when:

  • Creating components, services, and directives
  • Setting up state management with Signals
  • Writing unit, component, and E2E tests
  • Optimizing bundle size and runtime performance
  • Implementing forms, routing, and SSR

Categories

CategoryRulesImpact
Bundle Optimization5CRITICAL
Signals & Reactivity5HIGH
Change Detection5HIGH
Component Patterns4HIGH
RxJS Patterns5HIGH
Testing6HIGH
TypeScript14MEDIUM

Optional Library Skills

Install library-specific rules alongside this core skill:

LibraryInstall Command
NgRxnpx skills add alfredoperez/​angular-best-practices/​skills/​angular-best-practices-ngrx
SignalStorenpx skills add alfredoperez/​angular-best-practices/​skills/​angular-best-practices-signalstore
TanStack Querynpx skills add alfredoperez/​angular-best-practices/​skills/​angular-best-practices-tanstack

Quick Reference

Modern Angular Patterns

PatternUseAvoid
Signal inputsinput<T>()@Input()
Signal outputsoutput<T>()@Output()
Dependency injectioninject()Constructor injection
Control flow@if, @for, @switch*ngIf, *ngFor
Class binding[class.active][ngClass]
Change detectionOnPushDefault
Derived statecomputed()Getters

Component Template

@Component({
  selector: 'app-user-card',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    @if (user(); as u) {
      <h2>{{ u.name }}</​h2>
      <button (click)="selected.emit(u)">Select</​button>
    }
  `,
})
export class UserCardComponent {
  user = input.required<User>();
  selected = output<User>();
}

Service Template

@Injectable({ providedIn: 'root' })
export class UserService {
  private http = inject(HttpClient);

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>('/​api/​users');
  }
}

State with Signals

export class CounterComponent {
  count = signal(0);
  doubled = computed(() => this.count() * 2);

  increment() {
    this.count.update(c => c + 1);
  }
}

License

MIT