1. What is new in Angular 22?
Answer:
Angular 22 continues Angular's modern direction around:
- Standalone APIs
- Signals and signal-based reactivity
- Improved control flow
- Zoneless change detection
- Better TypeScript support
- Improved build and development tooling
- Performance improvements
- Modern Angular template syntax
- Improved SSR/hydration
- Continued reduction of legacy APIs
For an Angular 21 developer, the important point is that Angular 22 is primarily an evolution of the modern Angular architecture rather than a completely different framework.
2. What Angular version should you use with Angular 22?
Answer:
Angular 22 should be used with the Node.js and TypeScript versions officially supported by Angular 22.
In an upgrade, I would not manually guess these versions. I would first check Angular's version compatibility table and then upgrade the Angular CLI/framework and TypeScript together.
3. What is the difference between Angular 21 and Angular 22?
Answer:
Angular 22 builds on the APIs introduced and stabilized in recent Angular versions.
The major architectural direction remains:
Standalone components ↓ Signals ↓ Modern control flow ↓ Zoneless change detection ↓ Faster builds + better SSR
So an Angular 21 application that already uses standalone components, signals and modern control flow generally has a smoother upgrade path.
4. Are NgModules still required in Angular 22?
Answer:
No.
Angular supports standalone components, directives and pipes, so a new application generally doesn't need NgModule.
Example:
@Component({ selector: 'app-user', standalone: true, imports: [CommonModule], template: `...` }) export class UserComponent {}
In modern Angular, standalone APIs are the preferred architecture.
5. What are standalone components?
Answer:
A standalone component manages its own dependencies through the imports property instead of being declared inside an NgModule.
Example:
@Component({ selector: 'app-user', imports: [UserCardComponent, ReactiveFormsModule], templateUrl: './user.component.html' }) export class UserComponent {}
This makes components more self-contained and improves application structure and lazy loading.
6. What are Angular Signals?
Answer:
Signals are Angular's reactive primitive for representing state.
Example:
count = signal(0); increment() { this.count.update(value => value + 1); }
Template:
<p>{{ count() }}</p>
A signal tracks where its value is read and allows Angular to efficiently determine what needs to update.
7. What is the difference between signal() and computed()?
Answer:
signal() represents writable state:
count = signal(10);
computed() represents derived read-only state:
doubleCount = computed(() => this.count() * 2);
If count changes, doubleCount automatically recalculates.
8. What is effect()?
Answer:
effect() runs code whenever the signals it reads change.
effect(() => { console.log(this.count()); });
It is generally useful for side effects, such as logging, synchronization or interacting with APIs/browser APIs.
It should not normally be used to calculate derived state. computed() is more appropriate for derived state.
9. Signals vs RxJS — which should you use?
Answer:
They solve different problems.
| Signals | RxJS |
|---|---|
| Application state | Asynchronous streams |
| Synchronous reactive state | HTTP/event streams |
| Derived state | Operators |
| UI reactivity | Complex async workflows |
For example:
user = signal<User | null>(null);
is suitable for local UI state.
But:
this.http.get<User>('/api/user')
naturally produces an Observable.
Angular applications can use both Signals and RxJS together.
10. What is toSignal()?
Answer:
toSignal() converts an Observable into a Signal.
user = toSignal( this.userService.getUser() );
Then:
{{ user()?.name }}
This is useful when an application has RxJS-based services but wants signal-based component state.
11. What is toObservable()?
Answer:
toObservable() converts a Signal into an Observable.
count = signal(0); count$ = toObservable(this.count);
This is useful when integrating signal-based state with existing RxJS pipelines.
12. What is Angular's new control flow syntax?
Answer:
Modern Angular provides:
@if @else @for @switch
Example:
@if (user()) { <p>{{ user().name }}</p> } @else { <p>No user</p> }
Instead of:
<div *ngIf="user">
13. What is @for?
Answer:
@for is Angular's modern looping syntax.
@for (user of users(); track user.id) { <div>{{ user.name }}</div> }
The track expression helps Angular identify items efficiently when the collection changes.
14. Why is track important in @for?
Answer:
It allows Angular to identify which DOM elements correspond to which data items.
For example:
@for (user of users; track user.id) { <app-user [user]="user" /> }
If the array changes, Angular can reuse existing DOM elements instead of unnecessarily recreating them.
15. What is the difference between @if and *ngIf?
Answer:
Traditional:
<div *ngIf="isLoggedIn">
Modern:
@if (isLoggedIn) { <div>Welcome</div> }
The new control-flow syntax is built into Angular's template syntax and doesn't rely on structural directives in the same way.
16. What is zoneless Angular?
Answer:
Zoneless Angular allows Angular applications to perform change detection without relying on zone.js to detect asynchronous activity.
Modern Angular can use explicit reactive notifications such as:
- Signals
- Component input changes
- Events
- Template bindings
- Other Angular notifications
This can reduce unnecessary change detection work.
17. Why is zoneless change detection important?
Answer:
Traditional Angular commonly relies on Zone.js to determine when asynchronous operations might require change detection.
That can cause Angular to perform checks more broadly than necessary.
Zoneless Angular allows Angular to use more precise notifications, potentially improving:
- Performance
- Startup
- Runtime efficiency
- Predictability
18. Is Zone.js completely removed from Angular?
Answer:
No. Angular supports applications using Zone.js, while modern Angular also supports zoneless change detection.
Therefore, during migration, applications don't necessarily have to remove Zone.js immediately.
19. What is ChangeDetectionStrategy.OnPush?
Answer:
OnPush tells Angular that a component doesn't need to be checked under all traditional change-detection circumstances.
Example:
@Component({ changeDetection: ChangeDetectionStrategy.OnPush })
Angular checks the component when relevant triggers occur, such as input changes, events, or reactive updates.
20. Is OnPush still useful with Signals?
Answer:
Yes, although Signals provide much more precise reactivity.
For example:
@Component({ changeDetection: ChangeDetectionStrategy.OnPush }) export class UserComponent { user = signal<User | null>(null); }
Signals work naturally with Angular's modern change-detection architecture.
21. What is dependency injection in Angular?
Answer:
Dependency Injection allows Angular to provide required services instead of components creating them manually.
Example:
private userService = inject(UserService);
Angular manages the dependency's lifecycle and scope according to its provider configuration.
22. What is the inject() function?
Answer:
inject() provides dependencies without requiring constructor parameters.
Traditional:
constructor(private userService: UserService) {}
Modern:
private userService = inject(UserService);
It can make dependency declarations more concise and works in Angular's supported injection contexts.
23. What is the difference between providedIn: 'root' and component providers?
Answer:
@Injectable({ providedIn: 'root' })
creates an application-level singleton in the normal case.
Component-level:
@Component({ providers: [UserService] })
creates a service instance associated with that component's injector hierarchy.
24. What is Angular's hierarchical dependency injection?
Answer:
Angular has multiple injector levels.
A simplified hierarchy is:
Environment/Application Injector ↓ Route Injector ↓ Component Injector ↓ Child Component Injector
Angular searches the injector hierarchy to resolve dependencies.
25. What is lazy loading in Angular?
Answer:
Lazy loading means loading application code only when it is required.
Example:
{ path: 'users', loadComponent: () => import('./users.component') .then(m => m.UsersComponent) }
This reduces the initial JavaScript bundle.
26. What is loadComponent()?
Answer:
loadComponent() lazy-loads a standalone component.
{ path: 'dashboard', loadComponent: () => import('./dashboard.component') .then(m => m.DashboardComponent) }
This is commonly used in modern standalone Angular applications.
27. What is loadChildren()?
Answer:
loadChildren() lazy-loads routes.
{ path: 'admin', loadChildren: () => import('./admin.routes') .then(m => m.ADMIN_ROUTES) }
It is useful for larger route sections.
28. What is Angular SSR?
Answer:
SSR means Server-Side Rendering.
Instead of generating the initial HTML entirely in the browser, Angular renders the application on the server and sends HTML to the client.
Benefits include:
- Better initial rendering
- SEO benefits
- Faster perceived loading
29. What is hydration?
Answer:
Hydration allows Angular to reuse server-rendered DOM rather than destroying it and recreating the entire DOM on the client.
Conceptually:
Server ↓ HTML ↓ Browser ↓ Angular hydrates existing DOM
This can significantly improve SSR applications.
30. What is incremental hydration?
Answer:
Incremental hydration allows portions of an SSR application to become interactive based on defined conditions rather than hydrating the entire application immediately.
This can improve initial performance for large applications.
31. What is a route resolver?
Answer:
A resolver loads data before activating a route.
Example:
{ path: 'user/:id', component: UserComponent, resolve: { user: userResolver } }
The component can then receive the resolved data.
32. What is an Angular interceptor?
Answer:
An HTTP interceptor allows you to intercept HTTP requests and responses.
Common uses:
- Authentication tokens
- Logging
- Error handling
- Headers
- Retry logic
- Request timing
Modern Angular commonly uses functional interceptors.
export const authInterceptor: HttpInterceptorFn = (req, next) => { return next(req); };
33. Functional interceptor vs class interceptor?
Answer:
Modern Angular encourages functional interceptors.
Functional:
export const authInterceptor: HttpInterceptorFn = (req, next) => { return next(req); };
They are generally simpler and compose well with Angular's functional APIs.
Class-based interceptors remain relevant in existing applications.
34. How do you handle HTTP errors?
Answer:
this.http.get('/api/users') .pipe( catchError(error => { console.error(error); return throwError(() => error); }) );
For application-wide behavior, an HTTP interceptor can centralize error handling.
35. What is the difference between Subject and BehaviorSubject?
Answer:
Subject doesn't have an initial/current value.
const subject = new Subject<number>();
BehaviorSubject requires an initial value and provides the latest value to new subscribers.
const subject = new BehaviorSubject<number>(0);
36. What is switchMap() used for?
Answer:
switchMap() switches to a new Observable and unsubscribes from the previous one.
A common example is search:
searchText$.pipe( switchMap(text => this.http.get(`/api/search?q=${text}`) ) );
If the user types again before the previous request completes, the previous stream is cancelled/unsubscribed.
37. What is the difference between switchMap, mergeMap, concatMap, and exhaustMap?
Answer:
| Operator | Behavior |
|---|---|
switchMap | Cancel previous |
mergeMap | Run concurrently |
concatMap | Run sequentially |
exhaustMap | Ignore new values while current one runs |
Typical examples:
Search → switchMap Parallel API → mergeMap Queue → concatMap Submit button → exhaustMap
38. How do you prevent memory leaks in Angular?
Answer:
Modern Angular provides takeUntilDestroyed().
this.service.data$ .pipe(takeUntilDestroyed()) .subscribe(data => { // ... });
Other approaches include:
-
asyncpipe - Signals
- Proper Observable lifecycle management
- DestroyRef
39. What is DestroyRef?
Answer:
DestroyRef allows code to register cleanup logic when an Angular context is destroyed.
It can also be used with APIs such as takeUntilDestroyed().
40. What is Angular Reactive Forms?
Answer:
Reactive Forms represent form state in TypeScript.
Example:
form = new FormGroup({ name: new FormControl(''), email: new FormControl('') });
They are useful for complex forms, validation and dynamic form structures.
41. Template-driven vs Reactive Forms?
Answer:
| Template-driven | Reactive |
|---|---|
| Template-focused | TypeScript-focused |
| Simpler forms | Complex forms |
[(ngModel)] | FormControl |
| Less explicit | More explicit |
| Smaller forms | Enterprise forms |
For large enterprise Angular applications, Reactive Forms are commonly preferred.
42. What are Angular route guards?
Answer:
Route guards control navigation.
Examples include:
- Authentication
- Authorization
- Unsaved changes
- Feature access
Modern Angular commonly uses functional guards:
export const authGuard: CanActivateFn = () => { return inject(AuthService).isLoggedIn(); };
43. What is the difference between CanActivate and CanDeactivate?
Answer:
CanActivate controls whether a route can be entered.
User → /admin ↓ CanActivate?
CanDeactivate controls whether the user can leave a route.
Typical example:
Edit form ↓ User clicks another page ↓ Unsaved changes?
44. How do you optimize Angular application performance?
Answer:
Important techniques include:
- Lazy loading
-
@defer - Signals
-
OnPush - Zoneless change detection where appropriate
-
Proper
trackexpressions - Avoiding unnecessary subscriptions
- Image optimization
- SSR/hydration where appropriate
- Reducing bundle size
- Avoiding unnecessary component recreation
45. What is @defer?
Answer:
@defer allows Angular to defer loading/rendering of a section until it is needed.
Example:
@defer { <app-heavy-component /> }
You can also define placeholders:
@defer { <app-heavy-component /> } @placeholder { <p>Loading...</p> }
This can improve initial page loading.
46. What are the triggers available with @defer?
Answer:
Angular supports triggers such as:
@defer (on viewport) { ... }
Other triggers include conditions based on:
- Interaction
- Hover
- Immediate loading
- Idle
- Timer
- Custom conditions
This allows developers to control when expensive UI becomes available.
47. What is a custom directive?
Answer:
A directive changes the behavior or appearance of an existing DOM element or component.
Example:
@Directive({ selector: '[appHighlight]' }) export class HighlightDirective { }
It can be used as:
<div appHighlight> Hello </div>
48. What is the difference between a directive and a component?
Answer:
A component is essentially a directive with its own template.
Component ├── Template ├── Logic └── Styles Directive ├── Behavior └── No own template
A directive generally modifies an existing element/component.
49. How would you upgrade an Angular 21 application to Angular 22?
Answer:
I would follow a controlled upgrade process:
1. Check Angular 22 compatibility 2. Verify Node.js version 3. Verify TypeScript version 4. Check Angular Material/CDK compatibility 5. Check third-party libraries 6. Create upgrade branch 7. Update Angular CLI/framework 8. Run migrations 9. Update deprecated APIs 10. Run unit tests 11. Run build 12. Check SSR if applicable 13. Run lint/security checks 14. Test critical workflows 15. Compare bundle/build output 16. Deploy to lower environment
I would not manually modify package versions randomly, especially for an enterprise project with many dependencies.
50. What would you check before upgrading Angular 21 → Angular 22 in a real enterprise project?
Answer:
This is a strong senior-level interview answer:
"Before upgrading, I would first check Angular's official version compatibility matrix for Node.js, TypeScript and related packages. Then I would inspect the existing
package.jsonand identify Angular packages, Angular Material/CDK, RxJS and third-party libraries that have Angular 22 peer-dependency requirements. I would review the Angular migration/deprecation guide, create a dedicated upgrade branch, run the official Angular migrations, and then validate compilation, unit tests, production builds, lazy-loaded routes, forms, HTTP interceptors, SSR if used, and critical business workflows. I would also check bundle-size and security reports before and after the upgrade. Finally, I would deploy to a lower environment for regression testing before promoting it further."
No comments
Post a Comment