Frontend MasteryAngular & TypeScriptJune 2026

The Angular Interview
Authority.

23+ expert-level questions covering Signals, OnPush, Standalone Components, SSR hydration, and enterprise architecture. No textbook definitions โ€” just the depth interviewers actually probe.

23
Questions
5
Modules
4
Difficulty levels

Angular interviews in 2026 look fundamentally different from what they did two years ago. The framework has shipped Signals, standalone components, the new @if / @for template syntax, non-destructive hydration, and experimental zone-less mode. Interviewers at product companies expect candidates to understand not just the API surface, but why these changes happened โ€” what limitations they solved and what trade-offs they introduced.

This guide is built around that reality. Every answer goes beyond the definition to include real-world consequences, common production pitfalls, and the kind of โ€œwhy notโ€ reasoning that separates senior candidates from mid-level ones.

01
Module 01Junior

Angular Core Foundations

These questions appear in every Angular screen, at every level. Getting them wrong signals poor fundamentals. Getting them right โ€” with depth and real-world context โ€” immediately separates you from the pack.

Q01Junior

What is Angular and how does it differ from a library like React?

Angular is a complete, opinionated front-end platform built and maintained by Google. It ships with everything you need to build a large-scale SPA: a component model, a router, an HTTP client, a forms library, dependency injection, and a CLI โ€” all integrated and versioned together. React, by contrast, is a UI rendering library. React gives you the view layer and lets you choose your own router (React Router), state manager (Redux, Zustand), and data-fetching layer. The practical consequence: Angular projects tend to have more consistent conventions across teams because the framework makes those decisions for you. The tradeoff is that Angular has a steeper initial learning curve (TypeScript is mandatory, the DI system requires understanding) but a shallower long-term learning curve because there are fewer architectural decisions to make.

Practical note

Angular is often chosen for enterprise teams where 10+ developers need to onboard consistently. React is common in startups where flexibility and speed of iteration matter more.

Q02Junior

Why does Angular use TypeScript instead of plain JavaScript?

TypeScript gives Angular three structural advantages. First, the Angular compiler (Ivy) uses type information to generate optimised, tree-shakeable code at build time โ€” it can statically analyse your templates and eliminate dead code. Second, strong typing catches entire categories of bugs before runtime: incorrect component @Input types, missing required constructor parameters, wrong method signatures in services. Third, it dramatically improves tooling โ€” IDE autocompletion for component selectors, template property names, and injected service methods all rely on type information. Angular uses TypeScript decorators (@Component, @Injectable, @NgModule) to attach metadata to classes โ€” metadata the framework reads at runtime or compile time to wire up the component tree. This pattern simply isn't practical without TypeScript's type system.

Practical note

A concrete benefit: if you rename a service method in TypeScript, your IDE immediately highlights every broken call site. In plain JavaScript, the break is silent until runtime.

Q03Junior

What is an Angular Component and what does its decorator actually do?

A component is the fundamental building block of an Angular UI. It pairs a TypeScript class (behaviour) with an HTML template (structure) and optional CSS (presentation). The @Component decorator is what makes a plain TypeScript class into an Angular component โ€” it attaches metadata that tells the Angular compiler three critical things: the selector (the HTML tag name that instantiates this component), the template (inline or via templateUrl), and the styles. When Angular's compiler encounters your selector in a parent template, it creates an instance of the class, renders the template into the DOM, and sets up change detection to keep the view in sync with the class properties. Components communicate with parents via @Input (receiving data down) and @Output (emitting events up) โ€” this uni-directional data flow is the architectural spine of any Angular app.

Practical note

The selector follows CSS selector rules. Most components use element selectors (app-header), but you can also use attribute selectors ([appHighlight]) โ€” that's exactly how directives work.

Q04Junior

Explain the four types of data binding in Angular and when to use each.

Interpolation ( {{ value }} ) reads a component property and renders it as text in the template โ€” read-only, one-way from class to view. Property binding ( [property]="expression" ) sets a DOM property or @Input to the result of a TypeScript expression โ€” also one-way class-to-view, but for non-string values like booleans, numbers, or objects. Event binding ( (event)="handler()" ) calls a component method when a DOM event fires โ€” one-way view-to-class. Two-way binding ( [(ngModel)]="property" ) combines property and event binding: it keeps a form control in sync with a class property in both directions. Knowing when not to use two-way binding is as important as knowing how โ€” in performance-sensitive lists, two-way binding triggers change detection on every keystroke. Prefer one-way bindings with explicit form control groups in complex forms.

Practical note

The banana-in-a-box syntax [(ngModel)] = [ngModel] + (ngModelChange). If you see [()] in a template, there is always a @Input and a corresponding @Output EventEmitter behind it โ€” even on custom components.

Q05Junior

What is a Directive and how does it differ from a Component?

Every component is technically a directive with a template โ€” @Component extends @Directive. A pure directive modifies the behaviour or appearance of an existing DOM element without adding new template structure. There are two types. Structural directives (prefixed with *) change the DOM structure: *ngIf conditionally adds or removes an element, *ngFor stamps out a template for each item in an array, *ngSwitch switches between alternatives. Attribute directives change the appearance or behaviour of an element they're placed on: ngClass conditionally applies CSS classes, ngStyle applies inline styles, and custom directives can do anything from highlighting text on hover to managing scroll position. The * prefix on structural directives is syntactic sugar for Angular's <ng-template> desugaring โ€” *ngIf is compiled into [ngIf]="condition" on an <ng-template>.

Practical note

When you need to add behaviour to elements you don't own (e.g., a third-party date picker), an attribute directive is the right tool โ€” you can inject the host element reference and manipulate it without touching the third-party source.

Q06Junior

What is Dependency Injection in Angular and why is it better than manual instantiation?

Dependency Injection (DI) is a design pattern where a class declares its dependencies as constructor parameters, and an external system (the injector) creates and provides those dependencies. In Angular, when you mark a service with @Injectable({ providedIn: 'root' }), Angular registers it with the root injector as a singleton. Any component or service that lists it as a constructor parameter will receive the same instance. This is superior to manual instantiation (new MyService()) for three reasons: testability (in unit tests, you inject a mock instead of the real service, without changing the component), lifecycle management (Angular handles creation and cleanup), and scope control (services can be singleton at root, module-scoped, or component-scoped by changing the providedIn value).

Practical note

providedIn: 'root' uses tree-shaking: if no component ever injects the service, it's excluded from the bundle entirely. Listing a service in providers[] on a module always includes it, even if unused.

02
Module 02Mid

Services, Routing & RxJS

Mid-level questions probe whether you understand not just the API surface but the patterns underneath it. Interviewers at this level want to see that you can design a service layer, reason about async data, and avoid the most common RxJS pitfalls.

Q01Mid

How should you design Angular services and what is the single responsibility principle in that context?

An Angular service should own one concern: either data fetching, or business logic, or state management โ€” not all three. A common anti-pattern is a 'GodService' that makes HTTP calls, transforms the response, holds the current user state, and manages UI loading flags simultaneously. When that service needs testing, you have to mock everything at once. A better structure: an ApiService handles raw HTTP (one method per endpoint, returns Observable<RawType>), a DataTransformerService maps raw types to domain models, and a StateService holds the current application state as BehaviourSubjects that components subscribe to. This separation means a bug in the API layer doesn't require you to touch the state layer, and each service can be unit-tested in isolation by mocking only its direct dependency.

Practical note

Rule of thumb: if your service's constructor has more than 3 injected dependencies, it's probably doing too much.

Q02Mid

What is lazy loading in Angular routing and how does it impact bundle size?

In eager loading (the default), all modules are bundled into the main chunk and downloaded on initial page load โ€” even if the user never visits those routes. Lazy loading defers module loading until the user navigates to a route, splitting the application into separate JavaScript chunks. You configure it in the router with loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule). The Angular CLI automatically creates a separate chunk for each lazy-loaded module during the build. For large enterprise apps, this can reduce the initial bundle from several MB to under 200KB, dramatically improving Time to Interactive. With Angular 17+, standalone components can be lazily loaded directly without wrapping them in a module, simplifying the pattern.

Practical note

Use the Angular CLI's --stats-json flag with webpack-bundle-analyzer to visualise which chunks are large and whether lazy loading is actually splitting them correctly.

Q03Mid

Observable vs Promise โ€” what are the real production differences beyond the basic definitions?

The basic difference (Promise = one value, Observable = stream) understates the practical gap. Observables are cancellable: if a user navigates away before an HTTP request completes, you can unsubscribe and the in-flight request is cancelled. Promises are not โ€” once created, they run to completion regardless. Observables are composable: you can chain, merge, filter, debounce, and retry using RxJS operators without nesting callbacks. A search-as-you-type feature requires debounceTime, distinctUntilChanged, and switchMap โ€” all impossible to express cleanly with Promises. Observables are lazy: no work happens until subscribe() is called, making them safe to pass around and compose before executing. HttpClient returns Observables for all of this. The one case where Promises are simpler: one-shot async operations like Angular's APP_INITIALIZER โ€” a single await reads cleaner than subscribe().

Practical note

switchMap is the operator that makes search autocomplete safe: it automatically cancels the previous inner Observable when a new emission arrives, preventing race conditions where a slow earlier response overwrites a fast later one.

Q04Mid

What is the difference between Reactive Forms and Template-Driven Forms, and when should you choose each?

Template-driven forms define the form logic in the template using ngModel directives โ€” Angular infers the FormControl structure from the template. They're quick to set up for simple forms (login, contact) but become unwieldy for complex validation, dynamic field addition, or programmatic control. Reactive forms define the form structure in TypeScript using FormGroup, FormControl, and FormArray. The form model exists entirely in the component class, making it easy to unit-test without a DOM, add dynamic validators, listen to value changes as an Observable, or build form arrays for lists of varying length. In 2026, reactive forms are the default choice for any non-trivial form โ€” the extra boilerplate is justified by testability and control. Template forms are acceptable for isolated, simple forms where a developer needs to iterate quickly.

Practical note

Reactive form value changes are an Observable: this.form.get('email').valueChanges.pipe(debounceTime(300)).subscribe(). This makes real-time validation and server-side uniqueness checks trivial.

Q05Mid

What is an HTTP Interceptor and what are the most common production use cases?

An HTTP Interceptor implements HttpInterceptor and intercepts every HttpRequest and HttpResponse passing through Angular's HttpClient. It sits between the component making a request and the actual HTTP call, allowing you to transform either. Common production use cases: authentication (automatically attaching a Bearer token to every outgoing request so components never handle auth headers), logging (recording response times and error codes to an analytics service), error handling (catching 401 responses globally and redirecting to login, or catching 500s and showing a toast notification), and request caching (intercepting GET requests and returning a cached response if available). Interceptors are registered in providedIn using withInterceptors() in Angular 17+ or via the HTTP_INTERCEPTORS token in older module-based apps.

Practical note

A clone-and-modify pattern is required: HttpRequest objects are immutable. You must call request.clone({ headers: ... }) to add headers โ€” mutating the original throws an error.

03
Module 03Advanced

Change Detection & Performance

Change detection is where Angular's performance lives or dies. Senior candidates are expected to understand the Default vs OnPush difference deeply, explain Zone.js's role, and articulate the transition to zoneless Signals โ€” because this is the direction the framework is heading.

Q01Senior

How does Angular's Default change detection strategy work and why can it be expensive?

Angular's Default strategy uses Zone.js to intercept every asynchronous operation in the browser: setTimeout, Promise resolution, XHR completion, DOM events. Whenever any of these fire, Angular assumes something might have changed and runs change detection starting from the root of the component tree, working downward through every component, checking every bound expression against its previous value. In a small app, this is fine. In a large app with dozens of components and complex data bindings, a single click event triggers checking every expression in the entire component tree โ€” potentially thousands of checks per interaction. The checks themselves are fast (Angular compiles them to simple equality comparisons), but in CPU-constrained environments (mobile, low-end devices), the accumulated cost causes visible jank.

Practical note

Use the Angular DevTools profiler (Chrome extension) to visualise change detection cycles. If you see the root component lighting up on every interaction, the Default strategy is doing unnecessary work.

Q02Senior

What does ChangeDetectionStrategy.OnPush actually guarantee and what are its gotchas?

OnPush tells Angular: 'Only check this component when (1) one of its @Input references changes, (2) an event originates from within this component or its children, or (3) an Observable it subscribes to via the async pipe emits.' The key word is reference: if you mutate an array or object in-place (items.push(newItem)), the @Input reference hasn't changed, so the component won't update โ€” even though the underlying data has. This is the most common OnPush gotcha. The fix is immutable updates: always return a new array (items = [...items, newItem]). OnPush is most effective when combined with immutable data patterns and the async pipe โ€” the async pipe triggers change detection when the Observable emits and automatically unsubscribes when the component is destroyed.

Practical note

A quick win: apply OnPush to all 'leaf' components (components with no children) first. They benefit the most and the risk of breaking anything is lowest.

Q03Senior

What is Zone.js and what are the advantages of going zone-less with Signals?

Zone.js is a library that monkey-patches browser APIs (setTimeout, addEventListener, fetch, etc.) to create 'zones' โ€” execution contexts that can track when async operations start and finish. Angular uses this to know when to trigger change detection without you explicitly calling detectChanges(). It's invisible magic that makes the developer experience smooth but has real costs: Zone.js adds ~70KB to your bundle, the monkey-patching can interfere with third-party libraries that use async APIs, and it leads to 'over-detection' (checking the entire tree after any async event). Angular Signals (stable since v17) offer an alternative: instead of Zone.js tracking everything, each Signal is a reactive cell that knows exactly which template expressions read it. When a Signal changes, only those specific expressions are re-evaluated โ€” no full tree traversal needed. Zone-less Angular apps (using provideExperimentalZonelessChangeDetection()) are faster, produce smaller bundles, and interop better with non-Angular code.

Practical note

Angular 19+ enables zone-less mode with experimental stability. Migrating an existing app requires auditing for uses of setTimeout and manual change detection triggers, but new projects can start zone-less from day one.

Q04Advanced

What are Angular Signals and how do they change the reactivity model?

A Signal is a reactive value container: const count = signal(0). Reading it inside a template or computed() expression registers a dependency; writing to it (count.set(1) or count.update(v => v + 1)) notifies every dependent expression to re-evaluate. computed() creates a derived Signal that caches its value and only recomputes when its source Signals change. effect() runs a side effect whenever its Signal dependencies change. This model is fundamentally different from the Zone.js + full-tree check approach: Angular now knows the exact set of DOM nodes that depend on each Signal, so updates are surgical. Signals also interop with RxJS via toSignal() and toObservable(), making gradual migration of existing Observable-heavy code practical. The key mental shift: instead of thinking 'what triggers change detection?', you think 'what value does this piece of UI depend on?'

Practical note

computed(() => items().filter(i => i.active)) is lazily evaluated and cached โ€” Angular only recalculates the filtered list when items() actually changes, not on every render.

Q05Advanced

What is the TrackBy function in *ngFor and when does omitting it cause real problems?

Without trackBy, Angular identifies list items by their position in the array. When the array changes (sort, filter, add, remove), Angular destroys and recreates DOM nodes for items that moved โ€” even if the underlying data is identical. For a list of 100 items where only one changes, Angular may destroy and recreate 99 DOM nodes unnecessarily. This is invisible for simple lists but causes real problems when items contain sub-components with their own state (form fields, animations, subscriptions) โ€” destroying those nodes loses all that local state. trackBy receives the item's index and the item itself, and returns a unique identifier (usually an ID). Angular uses this identifier to match DOM nodes to data items across re-renders, reusing nodes for items that haven't changed and only creating/destroying nodes for genuinely new/removed items.

Practical note

trackBy: (index, item) => item.id is the 99% solution. If your items don't have IDs, that's a sign your data model needs fixing โ€” not that trackBy is optional.

04
Module 04Senior

Architecture, DI & Enterprise Patterns

Senior-level Angular questions focus on architectural decisions: how you structure large applications, manage complex state, design the DI hierarchy, and make trade-offs between patterns. Expect to defend your choices with concrete reasons.

Q01Senior

Explain the Angular DI injector hierarchy and how it affects service scope.

Angular maintains a tree of injectors that mirrors the component tree. At the top is the root injector (created by bootstrapApplication or the root AppModule). Below it, each lazy-loaded route creates a child injector. Components can create further child injectors when they have their own providers array. When a component requests a service, Angular walks up the injector tree until it finds a provider. This hierarchy gives you precise scope control: a service registered at root is a singleton shared application-wide. The same service registered in a component's providers array creates a new instance scoped to that component and its descendants โ€” destroyed when the component is destroyed. This is critical for features like modals or multi-step flows where each instance needs its own isolated state without polluting global state.

Practical note

providedIn: 'root' is equivalent to listing the service in AppModule.providers[] but adds tree-shaking. Component-level providers (providers: [MyService] in @Component) are the correct pattern for instance-scoped state.

Q02Senior

Subject vs BehaviorSubject vs ReplaySubject โ€” when does the choice matter in production?

Subject emits values only to subscribers active at the moment of emission โ€” a subscriber who joins late misses all past values. BehaviorSubject stores the current value and immediately emits it to any new subscriber โ€” ideal for state (current user, selected theme, auth status) where a late subscriber still needs to know the current state. ReplaySubject stores the last N emissions and replays them to new subscribers โ€” useful for event logs or undo/redo stacks where a subscriber needs recent history but not necessarily all values. The most common production mistake: using Subject for shared state and wondering why components that initialise after the data loads show nothing. BehaviorSubject with an initial value (new BehaviorSubject(null)) and an async pipe in the template is the correct pattern for shared reactive state in Angular.

Practical note

Always expose BehaviorSubjects as Observables using asObservable() to prevent consumers from calling .next() directly: get currentUser$(): Observable<User> { return this._currentUser$.asObservable(); }

Q03Senior

What are Standalone Components and how do they simplify large-scale Angular architecture?

Before Angular 14, every component had to be declared in exactly one NgModule. Modules acted as compilation contexts and the mechanism for sharing imports (components, pipes, directives) between feature areas. As apps grew, module graphs became complex โ€” circular dependencies between modules, large 'shared' modules that imported everything, and confusion about which module owned which component. Standalone components declare themselves self-sufficient: they list their own imports directly in the @Component decorator using the imports array. There's no module to declare them in. They can be lazily loaded directly (loadComponent), used in other standalone components by simply importing them, and bootstrapped without AppModule. The Angular team now recommends standalone components as the default for new applications. The migration path from module-based to standalone is incremental โ€” the two styles can coexist.

Practical note

A standalone component's imports array replaces what used to be in the module's imports + declarations. If you need CommonModule directives (*ngIf, *ngFor), import them individually โ€” or switch to the new @if / @for control flow syntax.

Q04Senior

How does Angular SSR work in 2026 and what does partial hydration mean for performance?

Angular Universal (now built into @angular/ssr) renders the application on the server for the first request โ€” the browser receives a fully rendered HTML page rather than a blank shell waiting for JavaScript. This dramatically improves First Contentful Paint (FCP) and Core Web Vitals scores, and makes content visible to search engine crawlers without waiting for JS execution. The challenge is hydration: the browser must 'rehydrate' the server-rendered HTML by attaching Angular's event listeners and change detection without re-rendering the DOM from scratch. Angular 17 introduced non-destructive hydration โ€” Angular reconciles its internal state with the existing DOM rather than destroying and rebuilding it, eliminating the hydration flash. Partial hydration (experimental in Angular 19) goes further: components that are not visible or interactive on first load are not hydrated at all until needed, reducing Time to Interactive.

Practical note

A common SSR pitfall: code that accesses browser APIs (window, document, localStorage) crashes on the server. Use isPlatformBrowser() or Angular's inject(PLATFORM_ID) guard to conditionally run browser-only code.

05
Module 05Senior

State Management, AOT & Performance Mastery

The questions in this module separate candidates who can build features from those who can architect systems. Expect to discuss state management trade-offs, bundle optimisation, and the Angular compiler's role in performance.

Q01Senior

When should you choose NgRx over a Signals-based service for state management?

NgRx applies Redux patterns to Angular: unidirectional data flow, immutable state, actions as the only way to mutate state, and effects for side effects. The benefits become significant at scale: predictable state transitions (you can replay the action log to reproduce any bug), Redux DevTools time-travel debugging, and a shared vocabulary for large teams (everyone knows what an action, reducer, and selector are). The cost is boilerplate and ceremony โ€” for a mid-size application, NgRx can add hundreds of lines of infrastructure for state changes that a BehaviorSubject in a service would handle in 10. The practical heuristic: use NgRx when multiple features share complex state that needs to be auditable and time-travel debugged, or when the team is large enough that shared conventions outweigh boilerplate cost. For most features and most applications in 2026, a Signal-based service (signal store) with component inputs and outputs is simpler and faster.

Practical note

@ngrx/signals (the NgRx SignalStore) offers a middle ground โ€” structured state with Signals rather than RxJS, without the full Redux overhead.

Q02Senior

What is AOT compilation and what problems does it solve that JIT compilation has?

Just-In-Time (JIT) compilation ships the Angular compiler to the browser and compiles component templates at runtime on the user's device. This means slower startup (compiler runs in the browser), larger bundles (the compiler is included in the JS payload), and templates that can only have errors detected at runtime. Ahead-of-Time (AOT) compilation runs the compiler during the build step. The templates are converted to optimised JavaScript before they ever reach the browser, the compiler is excluded from the production bundle, and template errors (referencing a non-existent property, incorrect pipe usage) are caught at build time as compiler errors. Since Angular 9 (with the Ivy compiler), AOT is the default for production builds. The Ivy compiler also enables tree-shaking at the component level โ€” Angular features you don't use are excluded from the bundle automatically.

Practical note

A hidden benefit of AOT: template type-checking is now as strict as TypeScript itself. Enabling 'strictTemplates' in tsconfig.app.json makes template type errors as visible as regular TypeScript errors.

Q03Senior

What is the new Angular @if / @for / @switch control flow syntax and why does it replace *ngIf?

The built-in control flow syntax (introduced stable in Angular 17) replaces structural directives (*ngIf, *ngFor, *ngSwitch) with template-native syntax. @if (condition) { ... } @else { ... } is more readable, avoids the need to import CommonModule or NgIf into every standalone component, and enables the compiler to analyse branches statically. @for (item of items; track item.id) { ... } makes trackBy mandatory rather than optional โ€” the track expression is required syntax, which eliminates the performance footgun of forgetting trackBy. @switch enables exhaustiveness checking. The old structural directives still work and won't be removed, but the new syntax is recommended for all new code and is the pattern Angular's schematics generate.

Practical note

Migration is semi-automated: ng generate @angular/core:control-flow converts *ngIf and *ngFor to the new syntax across your codebase โ€” review the output before committing.

Deep DiveSignals in Practice

Signals vs Zone.js โ€” the real difference

The snippet below shows the same counter component implemented with Zone.js (traditional) and then with Signals (zone-less). The logic is identical; the reactivity model is not.

Traditional (Zone.js triggers full-tree CD)

@Component({
  template: `<p>{{ count }}</p><button (click)="inc()">+</button>`,
  changeDetection: ChangeDetectionStrategy.Default,
})
export class CounterComponent {
  count = 0;          // plain class property
  inc() { this.count++; }
  // Zone.js sees the click event โ†’ runs CD on the full tree
}

Signal-based (zone-less, surgical DOM update)

@Component({
  template: `<p>{{ count() }}</p><button (click)="inc()">+</button>`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CounterComponent {
  count = signal(0);  // reactive cell
  inc() { this.count.update(v => v + 1); }
  // Only the <p> binding re-evaluates โ€” no full tree check
}
Bundle impact

Zone-less apps exclude Zone.js (~70KB gzipped). For mobile-first products, this meaningfully improves initial load time.

Debugging benefit

Signals make data flow explicit and traceable. You can always answer 'what reads this value?' โ€” which was impossible with Zone.js.

Migration path

toSignal() wraps any Observable into a Signal, and toObservable() does the reverse. Existing RxJS code can coexist during gradual migration.

Day-before interview checklist

Quick review items that make the difference in the first 20 minutes.

Core

Can you explain the four data binding types with a concrete DOM example for each?

DI

Do you understand how component-level providers create scoped service instances?

RxJS

Can you explain why switchMap is essential for search-as-you-type โ€” not just what it does?

CD

Can you describe what happens step-by-step when a Signal changes in a zone-less app?

Forms

Do you know when reactive forms are worth the boilerplate over template-driven forms?

Perf

Can you identify three distinct things that trigger change detection in an OnPush component?

SSR

Can you explain the difference between full hydration and partial hydration and the performance impact?

Arch

Can you design a service layer for a feature with API calls, state, and business logic โ€” keeping responsibilities separate?

Angular FAQ

What is the difference between Angular Signals and RxJS Observables?

Signals are synchronous, always hold a current value, and automatically track dependencies โ€” ideal for UI state. RxJS Observables are asynchronous streams with no 'current value' concept, composable with operators, and suited for HTTP, events, and complex async flows. They're complementary: toSignal() converts an Observable to a Signal, and toObservable() does the reverse. Use Signals for component state; use Observables for data streams and async operations.

What are Standalone Components in Angular?

Standalone components are self-sufficient Angular components that declare their own imports directly in the @Component decorator, eliminating the need for NgModule declarations. Available since Angular 14 and now the recommended default, they simplify architecture, enable direct lazy loading, and reduce the module boilerplate that plagued large Angular codebases.

How does Angular's OnPush change detection work?

OnPush tells Angular to only check a component when one of its @Input references changes, an event fires within the component, or an Observable emits via the async pipe. The critical gotcha: mutating an array or object in-place (push, splice) does not change the reference, so the component won't update. Always use immutable patterns (spreading arrays, creating new objects) with OnPush.

When should I use NgRx for state management in Angular?

Use NgRx when multiple feature areas share complex state that benefits from Redux DevTools debugging, when the team is large enough to justify the convention overhead, or when auditability of state changes is a requirement. For most features and small-to-medium applications, a Signal-based service with BehaviorSubjects is simpler and faster to maintain.

What is Zone.js and why is Angular moving away from it?

Zone.js monkey-patches browser APIs to detect when async operations complete, triggering Angular's change detection automatically. It adds ~70KB to the bundle and causes over-detection (checking the full component tree after any async event). Angular Signals enable a zone-less mode where only the specific DOM nodes that depend on changed Signals are updated โ€” producing smaller bundles and more predictable performance.

Related Interview Guides

Good luck โ€” the best interviews feel like conversations.

Last updated June 2026 ยท Covers Angular 17โ€“19 LTS

Feedback

Live