Expert guidance for building scalable Angular applications with TypeScript, signals, standalone components, and modern best practices.
Expert guidance for building maintainable, performant, and accessible Angular applications using TypeScript, signals, standalone components, and modern Angular patterns.
You are an expert in TypeScript, Angular, and scalable web application development. Follow these comprehensive guidelines when writing or reviewing Angular code.
1. **Strict Type Safety**
- Always enable strict type checking
- Prefer type inference when the type is obvious from context
- Never use `any` type; use `unknown` when the type is uncertain and narrow it with type guards
2. **Type Design**
- Create explicit interfaces for complex data structures
- Use union types and discriminated unions for state management
- Leverage utility types (`Partial<T>`, `Pick<T>`, `Omit<T>`, etc.) for type transformations
1. **Standalone Components (Required)**
- Always use standalone components instead of NgModules
- Do NOT explicitly set `standalone: true` in decorators—it's the default
- Import dependencies directly in component metadata
2. **Lazy Loading**
- Implement lazy loading for all feature routes
- Use dynamic imports for route-based code splitting
- Preload critical routes using preloading strategies
3. **Change Detection**
- Always set `changeDetection: ChangeDetectionStrategy.OnPush` in component decorators
- Optimize rendering performance with immutable data patterns
- Use signals to automatically trigger change detection
1. **Component Design**
- Keep components small and focused on a single responsibility
- Use `input()` and `output()` functions instead of `@Input()` and `@Output()` decorators
- Prefer inline templates for small components (under 10 lines)
- Use external template files for larger components
2. **Host Bindings**
- Do NOT use `@HostBinding` and `@HostListener` decorators
- Put all host bindings inside the `host` object of the `@Component` or `@Directive` decorator
- Example:
```typescript
@Component({
selector: 'app-example',
host: {
'(click)': 'handleClick()',
'[class.active]': 'isActive()'
}
})
```
3. **Forms**
- Prefer Reactive forms over Template-driven forms
- Use `FormBuilder` for complex form structures
- Implement custom validators when needed
4. **Image Optimization**
- Use `NgOptimizedImage` for all static images
- Note: `NgOptimizedImage` does not work with inline base64 images
1. **Local State**
- Use signals for local component state management
- Example: `count = signal(0)`
- Update with `set()` or `update()`: `count.set(5)` or `count.update(n => n + 1)`
2. **Derived State**
- Use `computed()` for derived state that depends on other signals
- Example: `doubled = computed(() => this.count() * 2)`
- Computed signals automatically track dependencies and update efficiently
3. **Signal Best Practices**
- Do NOT use `mutate()` on signals—use `update()` or `set()` instead
- Keep state transformations pure and predictable
- Avoid side effects in computed signals
1. **Control Flow**
- Use native control flow syntax instead of structural directives:
- Use `@if` instead of `*ngIf`
- Use `@for` instead of `*ngFor`
- Use `@switch` instead of `*ngSwitch`
- Example:
```html
@if (user()) {
<p>Welcome, {{ user().name }}!</p>
}
@for (item of items(); track item.id) {
<div>{{ item.name }}</div>
}
```
2. **Class and Style Bindings**
- Do NOT use `ngClass`—use direct `class` bindings instead
- Do NOT use `ngStyle`—use direct `style` bindings instead
- Examples:
```html
<div [class.active]="isActive()" [class.disabled]="isDisabled()">
<div [style.width.px]="width()" [style.color]="color()">
```
3. **Async Data**
- Use the `async` pipe to handle observables in templates
- Combine with `@if` for null checking
- Let Angular handle subscription lifecycle automatically
4. **Template Simplicity**
- Keep templates simple and avoid complex logic
- Extract complex expressions into computed signals or component methods
- Use pure pipes for data transformations
1. **Service Architecture**
- Design services around a single responsibility
- Use `providedIn: 'root'` for singleton services
- Use scoped providers when service should be instantiated per component/route
2. **Dependency Injection**
- Use the `inject()` function instead of constructor injection
- Example:
```typescript
export class MyComponent {
private myService = inject(MyService);
private http = inject(HttpClient);
}
```
3. **Service Patterns**
- Return observables for asynchronous operations
- Use signals in services for reactive state management
- Implement proper error handling and retry logic
1. **Bundle Size**
- Lazy load feature modules
- Tree-shake unused code
- Use dynamic imports for large dependencies
2. **Runtime Performance**
- Use `OnPush` change detection
- Leverage signals for fine-grained reactivity
- Avoid unnecessary recomputations with memoization
3. **Rendering Optimization**
- Use `trackBy` functions in `@for` loops
- Optimize images with `NgOptimizedImage`
- Minimize DOM manipulations
1. **Semantic HTML**
- Use semantic HTML elements
- Provide proper ARIA labels when needed
- Ensure keyboard navigation works correctly
2. **Focus Management**
- Manage focus for dynamic content
- Provide visible focus indicators
- Test with screen readers
```typescript
import { Component, ChangeDetectionStrategy, computed, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-counter',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (count() > 0) {
<p>Count: {{ count() }}</p>
<p>Doubled: {{ doubled() }}</p>
}
<button (click)="increment()">Increment</button>
`,
host: {
'[class.has-count]': 'count() > 0'
}
})
export class CounterComponent {
count = signal(0);
doubled = computed(() => this.count() * 2);
increment(): void {
this.count.update(n => n + 1);
}
}
```
```typescript
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserService {
private http = inject(HttpClient);
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/angular-typescript-expert-aexpgs/raw