JS/TS fundamentals
7An interpreted, dynamically typed, multi-paradigm (imperative, OO, functional), single-threaded language (async via the event loop) that is prototype-based.
Not in the classical sense (Java/C#). It's prototype-based: inheritance via prototype, properties added on the fly. ES6
class is just syntactic sugar over prototypes.A blueprint defining the structure (properties) and behavior (methods) of objects, with a
constructor called on creation.A concrete object created from a class via
new. Analogy: class = mold, instance = cake.The concrete code fulfilling a contract defined by an
interface. The interface says what (signatures), the implementation says how (class X implements Y).A tree representation of the HTML page, exposed as an API to read/modify content, structure and style. In Angular we avoid direct manipulation and rely on binding and change detection.
A programming interface = a contract specifying how software exchanges data. Types: REST (HTTP), GraphQL, WebSocket (real-time), SOAP (XML, legacy).
Angular Core
21A TS class decorated with
@Component that controls a slice of the UI: decorator (metadata), template (HTML), logic (class).Modern 20262026: standalone by default (no
NgModule), OnPush recommended, input()/output() signal functions.Smart (container): business logic, injects services, makes calls, passes data down. Dumb (presentational): renders received
input(), emits via output(), no services, OnPush, highly reusable.Yes: parent→child via
input(), child→parent via output(), siblings via a shared service.Modern 20262026: for shared state, a signal-based service rather than a
BehaviorSubject.Layered architecture (presentation/application/domain/infrastructure) + standalone + lazy loading; tooling ESLint + Prettier + Husky + conventional commits; state signals (NgRx if complex); testing unit + E2E + coverage target; CI/CD build/test/deploy pipeline; docs README + Compodoc/Storybook.
Feature-based:
core/ (singletons, guards, interceptors), shared/ (reusable components/pipes), features/<context>/{domain,application,infrastructure,presentation}, layout/. Why: scalable, maintainable, lazy-loadable, easy to navigate.Feature-based (recommended), Layer-based (by technical type, less scalable), Atomic Design (atoms→pages), DDD (by domain, bounded contexts).
Standalone, no hesitation, since Angular 15+ (default since 17). Less boilerplate, explicit per-component imports,
loadComponent lazy loading, better tree-shaking. NgModule only survives in legacy code to migrate.No more
zone.js patching async APIs → change detection isn't triggered "magically everywhere". State becomes explicitly reactive via signals (a set/update notifies the framework). Benefits: lighter bundles, more predictable & performant CD.Modern 20262026: zoneless is stable in Angular 22 (
provideZonelessChangeDetection()).An
@Injectable TS class holding reusable business logic, backend communication (HTTP) and data sharing between components, provided via DI.A single (singleton) instance app-wide, available everywhere without imports, and tree-shakeable. Alternatives:
'any', route-level providers, or component-level providers: [] for a local instance.A pattern: dependencies are provided from outside instead of created inside the class. Wins: testability (easy mocks), decoupling, reuse, maintainability.
Modern 20262026: the
inject() function is often preferred over constructor injection.A pattern guaranteeing one instance of a class app-wide. In Angular,
providedIn: 'root' creates one automatically. Use cases: AuthService, ConfigService, global cache.Interpolation
{{ }}, property [prop], event (event), two-way [(ngModel)]; plus attribute [attr.x], class [class.active], style [style.color].In native HTML,
disabled is active as soon as it's present, even disabled="false". Use property binding: [disabled]="isDisabled".Classic:
*ngIf (+ else/then), *ngFor (index, first, last, trackBy perf-critical), [ngSwitch]/*ngSwitchCase.Modern 20262026: use the native control flow
@if / @for / @switch (Angular 17+, default) — @for requires a track.3 syntaxes: object
[ngClass]="{active: isActive}" (most common), array ['btn', role], or method getClasses(). For a single class, [class.active]="…" is more direct.A TS class that alters an element's behavior/appearance. 3 types: component (directive with template), structural (
@if/*ngFor), attribute (ngClass, custom via @HostListener/@HostBinding).A template transformation function. Built-ins:
uppercase, number, currency, percent, date, json, and async (auto subscribe/unsubscribe — key). Custom: @Pipe({name, standalone: true}) + transform(). Pure (default, recompute on reference change) vs impure (every CD, ⚠️ perf).You declare a
Routes array (path→component), Angular uses <router-outlet> as a placeholder and swaps content on navigation without a full reload (SPA). Wildcard ** for 404.A placeholder directive where Angular renders the active route's component (like a photo frame whose image changes with the URL).
Load a component/feature on demand via
loadComponent / loadChildren → smaller initial bundle, faster startup, bandwidth saved.RxJS & Signals
9An async stream emitting 0..N values over time: push-based, lazy (runs on
subscribe), can complete or error (next/error/complete).A special multicast, hot Observable (emits without subscribers), both Observable and Observer. Variants:
Subject, BehaviorSubject (initial + last value), ReplaySubject (last N), AsyncSubject (last on complete).Everywhere:
HttpClient (calls), form valueChanges (with debounceTime/switchMap), router paramMap, and service state. Best consumed with the async pipe.Modern 20262026, default = signal for synchronous UI state: simple API (
set/update/computed), no subscribe/unsubscribe, integrated with zoneless CD, direct value() read. I keep RxJS for genuinely async/event streams (HTTP, debounce, websockets, event orchestration). Interop via toSignal() / toObservable().Modern 20262026: a root
@Injectable service exposing private signals + derived computed + mutation methods (immutable set/update). Legacy approach: private BehaviorSubject + xxx$ = subject.asObservable() + .next([...current, item]).Creation
of/from/interval/timer/fromEvent; transform map/switchMap/mergeMap/concatMap; filtering filter/take/takeUntil/debounceTime/distinctUntilChanged; combination combineLatest/forkJoin/merge; utility tap/catchError/retry.switchMap: autocomplete (cancel the previous search). mergeMap: fire N independent parallel requests (file uploads). concatMap: preserve order (sequential action queue). exhaustMap: ignore triggers while one is in-flight (anti-double-click on a login button).
Modern 20262026, prefer: the
async pipe in templates and takeUntilDestroyed() in classes. Legacy: takeUntil(destroy$) + ngOnDestroy, or manual Subscription. Often, moving to signals removes the problem entirely.toSignal() subscribes immediately and needs an initial value (else undefined on first render) → set initialValue/type carefully. And toObservable() emits based on an effect: watch for duplicate emissions or timing if you expected strict "current value" semantics.Architecture & State
11Yes.
Modern 20262026: signals +
computed in a service for small/medium state (often enough). NgRx (Redux: actions/reducers/selectors/effects, DevTools, verbose but scalable) for large apps with complex mutations. Akita = middle ground.Criteria: sharing (how many features touch the state), mutation complexity, need for traceability/time-travel, team size. Small/medium → signal services. Heavy async side-effects + audit → NgRx (or NgRx SignalStore, which marries signals + structure). Don't over-architect a small app.
A request = method (GET/POST/PUT/PATCH/DELETE) + URL/endpoint + headers (Content-Type, Authorization) + body (POST/PUT/PATCH). Response = status (2xx success, 4xx client error, 5xx server error) + body.
An API whose architecture relies on HTTP: resources addressed by URL, operations via HTTP methods, stateless.
Create / Read / Update / Delete ↔ POST / GET / PUT (or PATCH for partial) / DELETE.
Readable, maintainable code: explicit naming, short single-responsibility functions, DRY, comments only when needed (code self-explains), SOLID principles.
Ports & Adapters: isolate business logic from technical details. The domain (pure) depends on nothing; ports (interfaces) are implemented by adapters (HTTP, DB). Benefits: domain testable without deps, swappable implementations.
A domain-centric approach: Ubiquitous Language (shared dev/business vocabulary), Bounded Contexts, Entities (identity), Value Objects (compared by value), Aggregates, Repository pattern (data-access abstraction).
Web Components: standards (Custom Elements, Shadow DOM, Templates) for framework-agnostic reusable components. Micro-frontends: app split into separately built/deployed features. Pros: autonomous teams, independent deploy; cons: complexity, duplication, perf (multi-bundles). Approaches: iframe, Web Components, Module Federation, Single-SPA.
Custom Element: web standard for custom HTML tags. Angular Elements (
@angular/elements, createCustomElement) turns an Angular component into a Web Component usable anywhere (React, Vue, vanilla).3 paths: Angular Elements (small components), Stencil (framework-agnostic design system), or shared headless logic (pure TS lib) + per-framework UI, sharing styles (CSS/tokens).
Performance
5The mechanism by which Angular detects state changes and updates the DOM. Default: checks the whole tree on each event (simple, can be slow). OnPush: checks only when an
input() changes (new ref), an internal event fires, an Observable emits (async), or markForCheck().Modern 20262026: in zoneless, signals trigger CD granularly — go OnPush + signals by default.
Measure (Angular DevTools profiler), then:
track on @for (avoid full re-render), OnPush, virtual scroll (cdk-virtual-scroll-viewport), pagination/lazy, avoid impure pipes and heavy template work, memoized computed.Without a tracking key, Angular destroys/recreates all DOM nodes when the list changes → costly and loses state (focus, animations). With
track item.id, it reconciles only what changed.SSR + hydration (incremental/
@defer), NgOptimizedImage for the LCP image, route lazy loading, reduce initial JS (standalone + esbuild tree-shaking), preconnect/preload critical resources, avoid CLS (reserved dimensions).APM/errors: Sentry, New Relic, Datadog. Logging: ELK, Splunk, CloudWatch. RUM/session: GA, Hotjar, LogRocket. Perf: Lighthouse, WebPageTest, Bundle/Source-Map Analyzer. Angular: Angular DevTools.
Testing & Tooling
10Write tests before code. Red→Green→Refactor cycle: failing test, minimal code to pass, cleanup. Setup: test framework, follow the cycle, coverage target, CI integration.
Unit (services, pipes, pure functions), integration (component + deps), E2E (critical flows, forms, nav).
Modern 20262026: Vitest as default Angular runner; AAA pattern (Arrange-Act-Assert).
Unit: isolated unit, fast (ms), many, mocked deps. E2E: full app from the user's view, slow (s/min), few, real deps. Follow the test pyramid (many unit, few E2E).
Stable selectors (
data-cy/data-testid, no fragile CSS), independent tests, data setup/teardown, explicit waits (no fixed wait), Page Object Pattern.Order:
data-cy/data-testid (best), then stable id, semantic classes as a last resort. Avoid: complex CSS (div > p:nth-child(2)), style classes (.btn-primary), text (fragile with i18n).Test: business rules, mappers/transformations, stores/state, critical flows. Don't test: the framework itself, third-party internals, generated code, trivial getters. Aim for value, not coverage % for its own sake.
TestBed that imports the standalone component directly (no test module). For signals, set state then read the render/computed (no zone tick in zoneless: trigger CD explicitly). Mock injected services via providers.The Angular CLI manages the bundler under the hood (config via
angular.json, no webpack.config.js). Locally: ng serve (HMR), ng build, ng build --watch. Rare customization via @angular-builders/custom-webpack.Modern 20262026: the CLI uses esbuild/Vite by default (much faster than Webpack).
Bundling, minification, tree-shaking (removes dead code), code splitting (lazy), HMR, source maps.
Markers that trigger pipeline actions: Git tags (
v1.0.0 → prod build/release/deploy), commit-message flags ([ci skip], [deploy]), branch patterns (main, release-*), environment tags (staging/production). Typical pipeline: commit → build → tests → lint → prod build → deploy.Accessibility
2Semantic HTML first (
button, ul/li), ARIA roles if needed (role="listbox"/option, aria-expanded, aria-activedescendant), full keyboard nav (arrows, Esc, Enter, Tab), visible focus and focus management (Angular CDK a11y: FocusTrap, LiveAnnouncer, cdkTrapFocus), associated labels.Overusing ARIA where native HTML suffices (
<div role="button"> instead of <button>), or aria-* that lies about real state (e.g. aria-hidden on a focusable element). Golden rule: no ARIA is better than bad ARIA.Soft skills & Lead
4Answer honestly per your profile: owned frontend Angular expertise (e.g. 80/20, or 70/30 if comfortable with Node/NestJS), adaptability, concrete examples. The message: "I deliver value across the chain; my strength is the front-end."
Onboarding (docs, pair programming, walkthrough), continuous learning (code reviews with constructive feedback, best practices, targeted RxJS/signals/routing sessions), progressive autonomy (increasing task complexity, room to fail), support (availability, regular feedback, not only negative).
Quantitative: PRs merged unaided, falling resolution time, PR acceptance rate, coverage held. Qualitative: autonomy (fewer questions), code quality, architecture proposals. Feedback: junior/team feedback, 1-on-1s. E.g. from 3-4 review round-trips per PR down to 1 in 3 months.
Bring it back to an objective criterion (perf, maintainability, cost, risk), run a spike/POC or a comparative ADR when possible, hear the other's "why", decide by making the trade-off explicit, and commit once decided (disagree & commit). A concrete example from your career beats theory.