Skip to content

Interview Guide · 2026 Edition

Angular
Senior

HTML, CSS, JavaScript, TypeScript, modern Angular, RxJS, browser internals, architecture, performance, testing, security, system design and technical leadership.

Modules
30
Concepts
282
Questions
350

Block 01

Web fundamentals

HTML, CSS, JavaScript and TypeScript, from first principles to advanced interview questions.

01

HTML complete: semantics, forms, media and SEO

HTML defines meaning, keyboard navigation, forms and the basis that search engines and assistive technologies consume.

Theory

Document and semantics
  • head contains metadata, title, links, preload and scripts. body contains the visible document. A clear title and description improve navigation and presentation in results.
  • header, nav, main, article, section, aside and footer describe the purpose of each region. Browsers and assistive technologies use that structure to expose landmarks. div and span group content without adding meaning.
  • Block and inline describe formatting context behavior, which CSS can change. The semantics of the element do not change when modifying display.
  • a navigates and requires an href; button performs an action. target=_blank requires an appropriate rel policy to restrict opener access.
Forms and content
  • Images need alt depending on function. picture, srcset and sizes allow formats and resolutions. Width and height reserve space and reduce CLS.
  • Video and audio support multiple source, track for subtitles and controls. An iframe creates another context; restrict it with sandbox, permissions and trusted origin.
  • Form associates label with control, uses name for submission, and takes advantage of native types. GET encodes to URL; POST sends body. The server validates all fields.
  • A button within a form has type submit by default. type=button represents an auxiliary action and prevents accidental sending. The submit semantics also allow you to submit with Enter and run native validation.
Loading, SEO and accessibility
  • A data table uses caption, thead, tbody, th cells and scope relationships. This structure associates every data cell with its headers. Tables used for layout communicate relationships that do not exist and make responsive design harder.
  • br introduces a break within the same content, such as an address or a poem. hr marks a thematic shift between blocks. The visual space between elements belongs to margin, padding or gap in CSS.
  • Scripts with defer download in parallel and execute after parsing, in order. async runs when downloading and does not preserve order. Modules differ and use defer by default.
  • Technical SEO includes HTML crawlable, canonical, robots, structured data, correct status, sitemap and rendering compatible with the content.

Example

<form (ngSubmit)="save()" [formGroup]="profileForm">
  <label for="email">Correo</label>
  <input id="email" type="email" autocomplete="email"
         formControlName="email" aria-describedby="email-error">
  <p id="email-error" role="alert">Ingresá un correo válido.</p>
  <button type="submit">Guardar</button>
</form>

Theme sources

Questions and answers

Label and attribute?See answer

The tag defines the element; The attribute configures information or behavior in its start tag. A property DOM represents the live state and may differ from the initial attribute.

id or class?See answer

id identifies an element within the document and is used for relationships, fragments and labels. class groups elements for styles or behavior.

How to create an accessible form?See answer

I associate labels, group options with fieldset/legend, use types and autocomplete, explain errors and move focus when the flow requires it.

ol or ul?See answer

ol communicates that the order modifies the meaning; ul groups elements without semantic sequence.

When do you use a link and when do you use a button?See answer

A link with href changes location and preserves native actions such as opening in another tab. A button executes an action in the interface. Choosing the right element brings keyboard, role and expectations without recreating them with JavaScript.

What does native form validation provide?See answer

Attributes such as required, type, min, max and pattern express constraints and allow feedback from the browser. The application can customize messages, but the server must repeat the validation because the client can modify it.

How do you feel about this topic?

02

CSS complete: cascade, layout, responsive and performance

CSS resolves the cascade before computing layout and paint. Classic questions begin with selectors; Senior-level questions reach stacking contexts, containment and visual stability.

Theory

Waterfall and box model
  • The cascade considers origin, importance, layers, specificity, scope and order. !important alters the order within the origin and creates maintenance cost.
  • Specificity counts IDs, classes/attributes/pseudo-classes and types/pseudo-elements. :where() provides zero specificity; :is() and :not() take the most specific argument.
  • Box model adds content, padding, border and margin. box-sizing: border-box includes padding and border within the declared size.
  • Margin separates boxes; padding expands the interior and background area. Vertical margins can collapse in block formatting context.
  • display: none removes the accessibility box and tree; visibility: hidden conserves space and hides; opacity: 0 preserves layout and can preserve interaction if you do not control it.
Layout and responsive
  • Position static follows flow; relative conserves space and creates reference; absolute exits the stream and uses containing block; fixed relates to viewport except transform ancestors; sticky changes depending on scroll container.
  • Flexbox organizes a dimension and distributes space; Grid controls rows and columns. min-width: 0 usually resolves overflow of flex children.
  • Responsive design combines fluid sizes, media queries, container queries, adaptive images and width limits. Breakpoints based on the point where the content stops working better resist device and layout changes.
  • Overflow can clip, scroll or create formatting context. text-overflow: ellipsis needs overflow and white-space restrictions.
  • z-index only compares within the same stacking context. Transform, opacity, positioned elements and isolation can create new contexts.
Composition and performance
  • A transition interpolates the change between two states; An animation cycles through keyframes even if it does not change a property by interaction. transform and opacity are usually executed in composition and avoid layout, while prefers-reduced-motion allows reducing non-essential movement.
  • BEM names Block, Element and Modifier; CSS Modules, Shadow DOM and Angular encapsulation resolve scopes with different models.
  • Preprocessors add syntax in build; Frameworks deliver utilities or components. None replaces cascade, layout or accessibility.
  • contain limits which parts of the tree can affect layout, paint, or style outside of an element. content-visibility: auto allows you to skip rendering content outside the viewport. Both tools reduce work, but change measurements, focus and accessibility if they are applied without checking the result.

Example

@layer reset, base, components, utilities;

@layer components {
  .card { container-type: inline-size; }
  @container (min-width: 36rem) {
    .card__body { display: grid; grid-template-columns: 2fr 1fr; }
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; }
}

Theme sources

Questions and answers

Flexbox or Grid?See answer

Flexbox distributes elements along an axis and allows wrapping. Grid defines a two-dimensional structure. An interface can use both at different levels.

Why is z-index: 9999 not working?See answer

The element can live within a stacking context that is below another. I compare ancestral contexts before uploading the number.

display:none or visibility:hidden?See answer

display:none removes box; visibility:hidden conserves its space. If you need to only visually hide and maintain readability, I use a proven visually-hidden pattern.

How do you avoid brittle CSS?See answer

I reduce specificity, define tokens and layers, limit scope, document variants and test states, sizes, themes and actual content.

How do you diagnose a z-index problem?See answer

I identify the stacking contexts of both elements and compare their ancestors, not just their numbers. transform, opacity, isolation, and certain positioned elements create contexts that limit where a descendant competes.

Media query or container query?See answer

A media query responds to the viewport or user preferences. A container query responds to the space available for the component. The second allows you to reuse the same piece in different layouts without knowing the page that contains it.

How do you feel about this topic?

03

JavaScript: types, coercion, scope and functions

These questions appear in frontend interviews of any level. A Senior answer explains the language rule, shows a failing case, and proposes a way to write predictable code.

Theory

Types and conversions
  • JavaScript has primitive types undefined, null, boolean, number, bigint, string, and symbol. Objects are compared by reference. typeof null returns object for a historical decision.
  • var has function scope, allows redeclaration and its declaration is raised. let and const have block scope and remain in the temporary dead zone until initialization. const sets the reference, it does not make the object immutable.
  • Coercion is the conversion of a value from one type to another. It is explicit when code calls Number(value), String(value), or Boolean(value), and implicit when the language converts because an operator or context requires another type. Forms, query parameters, DOM attributes, and storage return strings even when they represent numbers or booleans; converting and validating at that boundary prevents coercion from spreading into the domain.
  • When an operator needs to convert an object to a primitive, JavaScript runs the abstract ToPrimitive operation. It first honors Symbol.toPrimitive and, depending on the hint, checks valueOf and toString until it obtains a primitive. That is why [] becomes '', [1, 2] becomes '1,2', and a plain object usually produces '[object Object]'; the operator then continues with the required numeric or string conversion.
  • The + operator is special: after converting objects to primitives, it concatenates if either operand is a string; otherwise it performs numeric addition. 1 + '2' produces '12', while '5' - 2, '5' * 2, and '5' / 2 convert to number. Template literals force string conversion, while if, !, &&, and || use boolean conversion.
  • Conversions have important edge cases: Number('') and Number(null) produce 0, Number(undefined) produces NaN, and Boolean('false') is true because every non-empty string is truthy. Number requires the entire string to represent a number; parseInt('10px', 10) accepts a numeric prefix. Neither replaces validating range, format, and finiteness with Number.isFinite.
Scope, hoisting and closures
  • === compares type and value without coercion. Object.is differs in NaN and -0. == has useful cases, like value == null, but requires knowing its coercion table.
  • Falsy includes false, 0, -0, 0n, empty string, null, undefined, and NaN. An empty array or object is truthy.
  • A function declaration is raised with its body. A function expression follows the rules of its variable. The arrow functions capture this, arguments, and super from the environment; They do not serve as a constructor.
  • this depends on how a function is invoked: method call, call/apply/bind, constructor with new or arrow lexical binding. Extracting a method may lose the receiver.
  • A closure is the combination of a function and the lexical environment where it was created. The function can run after the outer call has finished and still resolve parameters and variables from that environment. makeCounter can declare let count = 0 and return a function that increments count; every call to makeCounter() creates a private, independent binding.
Functions, this and decisions
  • A closure preserves bindings, not a snapshot of their values. If a binding changes, the functions that close over it observe the current value. This enables private state and coordinated callbacks, but also explains bugs when several functions accidentally share the same mutable variable.
  • In a loop, var creates one function-scoped binding, so deferred callbacks usually read the final value. let creates a new binding for each iteration. Before let, an IIFE or factory received each iteration value and created a separate environment.
  • Closures support factories, currying, memoization, event handlers, and asynchronous callbacks. The environment remains alive while a reachable function needs it: that is not a leak by itself, but it can retain DOM nodes, caches, or large responses. Cleanup should remove listeners, cancel timers or subscriptions, and avoid capturing entire objects when an identifier or small value is enough.
  • The spread copies a level and lists properties. structuredClone covers many values ​​and cycles, but not functions or all host objects. A JSON round-trip misses dates, undefined, BigInt, and prototypes.
  • Destructuring extracts values and supports defaults. The default runs only for undefined, not for null. Rest groups the remainder and should occupy the last position.

Example

function makeCounter() {
  let count = 0;
  return () => ++count;
}

const first = makeCounter();
const second = makeCounter();
console.log(first(), first(), second()); // 1, 2, 1

console.log(1 + '2');       // '12'
console.log('5' - 2);       // 3
console.log(Number('42'));  // 42
console.log(Boolean(''));   // false
console.log([] == false);   // true
console.log([] === false);  // false

Theme sources

Questions and answers

What is the difference between var, let and const?See answer

var has function scope and allows redeclaration. let and const have block scope and remain in the Temporal Dead Zone until initialized. const prevents reassignment of the binding, but the referenced value can still mutate.

Why does [] == false give true?See answer

Abstract equality does not compare the array and boolean directly. It first converts false to the number 0. It then applies ToPrimitive to the array: [].toString() produces ''. Because it is now comparing a string with a number, it converts '' to 0; the final result is 0 == 0, which is true. In contrast, [] === false is false because the types differ and no coercion occurs. I would not memorize only this result: following boolean → number, object → primitive, and string → number also explains cases such as [0] == false. In production code I use === and explicit conversions so this sequence is not hidden.

Arrow function or normal function?See answer

I use arrow for callbacks that need the outer this. Use normal function for dynamic methods, constructors or APIs that assign receiver.

Shallow copy or deep copy?See answer

A shallow copy creates a new object or array, but nested values are copied by reference. For example, with const original = { user: { name: 'Ana' } }; const copy = { ...original };, copy !== original, but copy.user === original.user; therefore, copy.user.name = 'Luis' also changes original.user.name. Spread, Object.assign, Array.from, and slice make shallow copies. A deep copy recursively duplicates the structure so nested objects do not share identity. structuredClone(original) works for many native data types and cycles, but it does not clone functions or DOM elements, and it does not preserve the behavior of every class instance. I do not deep-clone by default: it costs CPU and memory and can break identities the application relies on. For state updates, I prefer copying only the changed path, such as { ...state, user: { ...state.user, name: 'Luis' } }; this preserves immutability and structural sharing without duplicating the entire object graph.

What is a closure, and when is it created?See answer

A closure is a function together with references to the bindings in its lexical environment. It is determined when the function is created, not when it is invoked. For example, function makeCounter() { let count = 0; return () => ++count; } returns a function that keeps accessing count after makeCounter finishes. const a = makeCounter(); const b = makeCounter(); creates two environments: a() returns 1, then 2, while b() starts at 1. The runtime preserves only environments that remain reachable, so a closure provides private state without turning count into a global variable.

Does a closure capture the value or the binding?See answer

It captures the binding—the cell where the value lives—not an immutable snapshot. With let rate = 1; const price = value => value * rate; rate = 2;, price(10) returns 20 because it reads the current value of rate. Several functions can share the same binding and observe its changes. If I need to freeze a value at a point in time, I create another binding by passing the value to a factory: const withRate = rate => value => value * rate. Each call receives its own rate parameter.

Why does a loop with var and callbacks usually print the final value?See answer

var has function scope, so every callback closes over one shared i binding. When the timer runs, the loop has finished and that binding is 3: for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); prints 3, 3, 3. With let, the specification creates a new binding for every iteration, producing 0, 1, 2. Another solution is a factory or IIFE that receives i and creates a distinct parameter for each iteration. The important point is not the timer: it is how many bindings exist and which one each function captures.

How can a closure retain unnecessary memory?See answer

While a function is reachable, the values it needs from its environment also remain reachable. A global listener that captures a component, a timer that captures a large response, or an unbounded cache can keep that graph alive after the view is removed. Not every closure is a leak: it becomes a problem when the reference outlives the useful lifetime of the data. I remove listeners, clear timers and subscriptions, limit caches, and capture only the necessary identifier or small value. In Angular I connect cleanup to DestroyRef or takeUntilDestroyed when appropriate.

What is the difference between implicit coercion and explicit conversion?See answer

With explicit conversion, the code states its intention: Number(input.value), String(id), or Boolean(flag). Implicit coercion occurs inside an operator or context: '5' - 1 produces 4, 1 + '2' produces '12', and if ('false') enters because the string is not empty. Coercion is not automatically an error; templates, comparisons, and operators depend on it. The risk appears when it hides a contract. At external boundaries I convert, validate, and keep a stable type from that point onward.

What is ToPrimitive, and why does it matter?See answer

ToPrimitive is the abstract operation that converts an object into a primitive value before another algorithm continues. If present, it calls Symbol.toPrimitive; otherwise it tries valueOf and toString in an order determined by the hint. They must return a primitive or conversion fails with a TypeError. That is why [] + 1 produces '1': the array becomes '' and + concatenates. An object can customize the result with [Symbol.toPrimitive](hint), but surprising behavior makes operators difficult to reason about; I normally prefer explicit domain methods.

Why does the Temporal Dead Zone exist?See answer

When JavaScript enters a block, it creates the bindings for let, const, and class, but leaves them uninitialized until their declaration executes. That interval is the Temporal Dead Zone. Reading the binding during it throws a ReferenceError: console.log(total); let total = 1;. Even typeof total fails when total is in the TDZ, unlike a variable that does not exist. With var, the binding is initialized to undefined, so early access does not fail and can hide an ordering bug. The TDZ prevents a block-scoped variable from being used before it has the value promised by its declaration. It does not mean let and const are not hoisted: their bindings are created when entering the scope, but they are not accessible yet.

Would you ever use ==?See answer

Yes, but I would deliberately use value == null only when I want to accept exactly null or undefined. The comparison is true for those two values and false for 0, false, '', and NaN; for example, if (response.middleName == null) detects that an optional field is missing without rejecting a valid empty string. This is a well-known Abstract Equality exception and should be allowed explicitly with a rule such as eqeqeq: ['error', 'always', { null: 'ignore' }]. Everywhere else I use === and !==, because == applies coercions that are difficult to read: '' == 0, '0' == false, and [] == false are all true. If the team prioritizes maximum explicitness, I write value === null || value === undefined; it communicates the same contract without relying on knowledge of the exception.

How do you feel about this topic?

04

JavaScript: objects, prototypes, arrays and functional programming

JavaScript uses prototypical delegation. Classes offer syntax, but objects still resolve properties through a chain of prototypes.

Theory

Basics
  • Object.create(proto) fixes the prototype. new C() creates an object, binds C.prototype, executes C with that this, and returns the object unless another object is explicitly returned.
  • A property can be owned or inherited. Object.hasOwn checks ownership; in loops through the chain. Object.keys returns own enumerable keys.
  • The property descriptors control writable, enumerable and configurable; getters and setters form accessors. Changing descriptors affects serialization and copying.
  • Arrays are objects with indexes and length. for...of loops through values ​​of an iterable; for...in loops through enumerable keys and is not suitable for arrays.
Mechanism and application
  • map creates a transformed collection, filter persists elements, reduce accumulates, find returns the first match, and some or every evaluates predicates. Each method communicates a different intention and avoids accumulating effects within a generic loop.
  • sort mutates and converts to string without comparator. toSorted, toReversed, toSpliced, and with return copies in modern runtimes.
  • A pure function depends on its arguments and produces no observable effects. Purity improves tests and composition, but an application needs effects at controlled boundaries.
Decisions and limits
  • Currying transforms a multi-argument function into a sequence of functions. Partial application sets some arguments; They are not identical concepts.
  • Memoization saves results associated with its arguments. The strategy needs an equality rule, a size limit, and an override policy; Without those limits, the cache can return stale data or retain memory uncontrollably.
  • Big O describes growth. Access by array index is usually O(1); linear search O(n); sort comparative O(n log n); average access to Map O(1). The constants still affect the user.

Questions and answers

Class or prototype?See answer

class organizes inheritance and methods with clearer syntax; the runtime resolves methods through prototypes. Knowing the model explains instanceof, shadowing and shared methods.

map or forEach?See answer

map creates a transformed collection and requires using the return. forEach expresses one effect per element and returns undefined.

Map or object?See answer

Map accepts any key, preserves insertion order, and offers size and direct iteration. An object fits into records with string/symbol keys and JSON serialization.

What mutates an array?See answer

push, pop, shift, unshift, splice, sort, reverse, fill and copyWithin. map, filter, slice, concat and the to* methods create another array.

What does a spread copy lose?See answer

Spread copies enumerable properties from the first level. Nested references remain shared and the copy does not preserve complete descriptors or internal behavior of all objects. First I define which part of the model needs a new identity.

When do you avoid chained map, filter and reduce?See answer

Each operator can loop through and assign another collection. On a hot route or a large list, a single loop can reduce memory and work. I keep the chain when its clarity outweighs that measured cost.

How do you feel about this topic?

05

JavaScript asynchronous: event loop, Promises and errors

JavaScript executes code in a single call stack and delegates timers, network and events to the environment. Promises, async/await, and the event loop allow you to coordinate when each operation continues without blocking the interface.

Theory

Execution model
  • Synchronous code finishes one instruction before starting the next. JavaScript uses a single call stack to execute that code in the browser's main thread. A slow function occupies the stack and delays clicks, input, layout and paint.
  • An asynchronous operation starts a job whose result will arrive later. The browser can handle a timer, network request, or event while the stack continues with other instructions. Asynchrony describes coordination over time; It does not mean that two fragments of JavaScript are executed at the same time in the same thread.
  • The event loop coordinates the call stack with the browser environment and its queues. Takes a task, executes its callback until the stack is empty, drains all pending microtasks, allows the browser to render, and then advances to another task. setTimeout, events and messages generate tasks; Continuations of Promises and queueMicrotask generate microtasks.
  • A Promise is an object that represents the future result of a single operation. It is born in state pending and ends as fulfilled with a value or rejected with a reason. fulfilled and rejected form state settled. A settled Promise cannot change state or reissue another result.
  • The new Promise(executor) constructor runs the executor immediately and synchronously. The functions resolve and reject set the eventual result; they do not make the job running inside the executor asynchronous. The asynchrony comes from the API used, such as fetch, a timer or IndexedDB. If an API already returns a Promise, wrapping it in another usually adds code and errors without providing control.
Promise and async/await
  • then records the success path, catch records the rejection path, and finally executes cleanup without receiving or replacing the result unless it throws an error. Each method returns a new Promise. That's why a chain does not modify the previous Promise: each link describes how to obtain the next result.
  • The value returned by a callback decides the next link. A common value meets the following Promise with that value; a Promise or thenable causes the next one to adopt its state; a throw rejects it. Skipping return delivers undefined and leaves any operations initiated within the callback out of the chain.
  • The then, catch and finally handlers do not run during the current stack, even though Promise is already settled. JavaScript queues them as microtasks. The browser drains that queue before taking on another task, so a chain that creates unfinished microtasks can delay timers, events, and renders.
  • A function declared with async returns a Promise. A return value produces a Promise fulfilled with value; a throw error produces a Promise rejected. await promise pauses only the execution of that function, frees the stack and resumes its continuation as a microtask when Promise finishes. await does not block the thread or move CPU work to another thread.
  • Two consecutive await typically execute operations in sequence when the second begins after the first is resolved. If both are independent, starting them earlier and waiting for Promise.all reduces the total time. Concurrency begins when you create or invoke operations, not when you type Promise.all.
Observable and streams
  • The combinators express different policies. Promise.all complies when all comply, preserves the input order and rejects upon the first observed rejection. Promise.allSettled awaits all results. Promise.race adopts the first settlement. Promise.any takes the first fulfillment and, if everyone rejects, returns a AggregateError.
  • A Observable represents a source that can send zero, one, or multiple values over time. A subscription connects an observer to that source. The observer can receive next notifications, a single error terminal notification, or a single complete terminal notification. After error or complete no more values ​​arrive.
  • Most RxJS Observables are lazy: the producer starts for every subscribe. A cold Observable creates a separate execution per subscriber, like an HTTP request. A Observable hot shares a source that it already produces, such as user events or a Subject. Operators such as map, filter, switchMap, and catchError create new Observables and describe the stream without mutating the source.
  • unsubscribe executes the teardown recorded by Observable and stops delivering notifications to that subscriber. Stopping the underlying work depends on the producer implementing that teardown. Angular HttpClient aborts request upon unsubscribing; A Observable of its own that starts a timer must cancel it in its cleanup function. Unsubscribing does not undo effects that have already occurred.
  • Promise and Observable model different contracts. A Promise shares a single settled result and is consumed with then or await. A Observable models a sequence, can be lazy, allows temporal compositing, and offers subscription teardown. Converting between the two can lose information: firstValueFrom takes the first value and needs the source to emit or terminate; converting a Promise to Observable does not make the original operation cancelable.
Cancellation, errors and performance
  • try/catch captures synchronous block errors and rejections that traverse a await. It does not catch an error thrown later by a disconnected callback, such as a setTimeout. That callback needs its own handling or should be part of a Promise that the flow returns and waits for.
  • A Promise does not define cancellation. AbortController allows you to ask fetch and other supported APIs to stop their work using a signal. Canceling the client avoids processing an unnecessary response, although the server can continue if it has already received and started the operation.
  • A race condition appears when several operations compete to update the same state and finish in a different order. A search engine may return an old response if the first request takes longer than the last. Abort the previous one, assign a version to each request or accept the result only if it still corresponds to the current query.
  • Debounce waits a period of no events before executing; It is used for searches while the user writes. Throttle imposes a maximum frequency; It is used to scroll or resize. Both need cleanup to cancel timers or pending work when the consumer is destroyed.
  • async/await organizes I/O waiting, but does not reduce the cost of synchronous code. I split CPU-intensive tasks into small tasks when you need to give control back to the browser. Use a Web Worker when the calculation deserves another thread and the cost of copying data and sending messages is acceptable.

Example

function delay(ms, value) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), ms);
  });
}

async function loadDashboard() {
  const userRequest = delay(300, { id: 7 });
  const settingsRequest = delay(200, { theme: 'dark' });

  try {
    const [user, settings] = await Promise.all([
      userRequest,
      settingsRequest,
    ]);
    return { user, settings };
  } catch (error) {
    throw new Error('No se pudo cargar el dashboard', { cause: error });
  }
}

console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
queueMicrotask(() => console.log('D'));
console.log('E');

// A, E, C, D, B
loadDashboard().then(console.log).catch(console.error);

Questions and answers

What is a Promise?See answer

A Promise represents a single result that may not yet be available. Starts pending and ends fulfilled with a value or rejected with an error. For example, fetch('/users') immediately returns a Promise; The object allows you to record what to do when the response or failure arrives. Promise does not contain a thread nor does it execute two results: it models the completion of an operation.

Is new Promise executor asynchronous?See answer

No. new Promise((resolve) => { console.log('executor'); resolve(1); }) prints executor during the current stack. What runs next as a microtask is the callback registered with then. Putting a heavy loop inside the executor blocks the interface just like any other synchronous code.

What does then return?See answer

then returns a new Promise. If the callback returns 42, the new Promise satisfies 42; if fetch(...) returns, it adopts the state of that Promise; If it throws an error, it is rejected. This contract allows chaining transformations and propagating errors up to a catch.

What happens if you forget return inside a then?See answer

The callback returns undefined, so the next then continues without waiting for the internal operation. On loadUser().then(user => { saveUser(user); }).then(showSuccess), showSuccess may execute before saveUser terminates. The fix is ​​return saveUser(user) or use await saveUser(user) inside a async function.

In what order do you print the example?See answer

First run the synchronous stack: A and E. The microtasks are then processed in the order in which they were queued: C and D. At the end the timer task runs and B appears. The result is A, E, C, D, B. A timer with zero delay indicates a minimum delay; it doesn't jump ahead of the stack or microtasks.

Does await block JavaScript?See answer

await pauses the containing function async and returns control to the caller. The main thread can process other tasks. When Promise finishes, JavaScript enqueues the continuation of the function as a microtask. A heavy calculation before or after await still blocks because await does not create another thread.

When to use sequential execution and when to use concurrent?See answer

Use sequence when an operation depends on the previous result, such as loading a user and then querying their permissions. For independent jobs, start both before: const userRequest = loadUser(); const settingsRequest = loadSettings(); const [user, settings] = await Promise.all([userRequest, settingsRequest]);. Thus the total time approximates the slower operation instead of adding both waits.

Promise or Observable?See answer

A Promise delivers a single result and does not incorporate cancellation. It starts when the operation that created it has already been started. A Observable can output zero, one, or multiple values; It usually starts when you subscribe, allows unsubscribe, and composes time, cancellation, and concurrency using operators. For an isolated HTTP request a Promise can be achieved; for cancelable events, streams, or flows, a Observable better expresses the contract.

What is a Observable and what does subscribe do?See answer

A Observable describes how to produce and deliver a sequence of notifications. subscribe starts or connects that production and returns a Subscription. The observer receives next(value) while there is data and can then receive complete() or error(reason) as an exclusive end. Example: interval(1000) emits values ​​until the consumer unsubscribes; http.get() usually issues a response and completes.

Observable cold or hot?See answer

A cold Observable creates one execution per subscriber. Two subscriptions to http.get('/users') usually create two requests. A hot Observable shares an external source or execution between subscribers, such as clicks or a Subject. share and shareReplay can share a cold source, but require defining replay, refCount and reset to not retain data or connections longer than expected.

Does unsubscribe always cancel the job?See answer

unsubscribe stops delivering values ​​and executes the teardown of the producer. It cancels the job only if that teardown knows how to stop it. HttpClient may abort the request; a Observable created with new Observable should return cleanup, for example return () => clearInterval(id). A Promise converted with from(promise) will still resolve because the original Promise does not know about the subscription.

When to convert a Promise to Observable or a Observable to Promise?See answer

from(promise) integrates a single result into a RxJS pipeline, but does not add cancellation to Promise. firstValueFrom(source$) resolves with the first issue and unsubscribes; lastValueFrom(source$) waits for the source to complete and uses the latest one. If the source is non-emitting or incomplete, the Promise may reject or be left pending, so the conversion needs a clear completion contract.

How do you cancel fetch?See answer

I create const controller = new AbortController(), pass controller.signal to fetch, and call controller.abort() when the response is no longer useful. The resulting rejection represents cancellation and not a functional error. I also clear the controller by destroying the component or by starting a request that replaces the previous one.

Why doesn't try/catch catch an error from setTimeout?See answer

The timer callback runs in another task, after the try block has finished. try { setTimeout(() => { throw new Error('boom'); }); } catch {} does not capture it. The callback needs to handle its error or the API needs to wrap the result in a Promise that the caller can return and wait for.

How do you prevent an old answer from replacing a new one?See answer

I save the identity of the current request, cancel the previous one, or compare a version before writing status. In a search engine, the query ang may answer after angular; Without that protection, the UI displays results that no longer match the input. In RxJS, switchMap expresses the policy of keeping only the most recent operation.

How can a chain of microtasks block the interface?See answer

The browser empties the microtask queue before advancing to the next task and rendering. A chain that schedules another microtask can delay input and painting. I split the work and defer to the scheduler when I need the browser to process another task.

What happens if a promise inside Promise.all fails?See answer

Promise.all rejects upon receipt of the first observable rejection, but remaining operations continue unless its API supports cancellation. I use allSettled when I need the result of each operation and AbortController when I need to stop compatible I/O.

How do you feel about this topic?

06

Advanced TypeScript

Angular amplifies TypeScript. A weak foundation in the language produces unsafe templates, mutable state, and RxJS that are difficult to maintain.

Theory

type system
  • TypeScript adds a static type system over JavaScript. The compiler checks the program and removes the types by issuing JavaScript; That is why a type does not validate data that arrives in runtime.
  • Inference deduces types from values and context. Structural typing considers two values ​​compatible when their form satisfies the contract, even if they do not share a class or nominal declaration.
  • A union expresses alternatives and narrowing rules out possibilities through typeof, in, instanceof, discriminants or type guards. A switch that delivers the remaining case to never detects new variants during compilation.
  • interface describes extensible contracts and supports declaration merging. type also represents unions, tuples, primitives, and computed types. The capacity needed by the model decides the choice.
  • TypeScript extends JavaScript with a static type system. The compiler checks the program and removes the types by issuing JavaScript; That is why an annotation does not by itself validate the data that arrives in runtime.
Narrowing and modeling
  • Inference obtains a type from the value and its context. An annotation establishes the contract explicitly. as const preserves literals and makes the inferred structure readonly, while a broad annotation can convert a literal such as 'open' to string.
  • TypeScript uses structural typing: two values are compatible when their form meets the required properties, even if their classes or names are different. Excess properties are checked more rigorously in object literals than in intermediate variables.
  • A interface describes object contracts and supports declaration merging. A type can also represent unions, intersections, primitives, tuples, and computed transformations. Both can express many object contracts.
  • A A | B union accepts any of its members and only allows common operations until the type is narrowed. A A & B intersection requires that the security satisfy both contracts at the same time.
  • Function signatures type parameters and returns. Overloads publish several valid forms of calls on an implementation, while optional parameters, rest and default values ​​model variations within the same signature.
Calculated and generic types
  • any disables checking for the value and allows the type gap to propagate. unknown accepts any value, but requires checking its type before trading on it.
  • never represents a value that cannot exist. It appears in non-returning functions and in exhaustive branches of a union, where it allows detecting unhandled variants during compilation.
  • A generic introduces type parameters. The relationship between input and output is preserved without being replaced by any; for example, a function identity<T>(value: T): T returns the same type as it received.
  • A discriminated union brings together variants that share a literal property, such as kind. When checking that property, TypeScript narrows the type and enables only the fields of the active variant. A case default assigned to never detects new states that are not yet handled.
  • The satisfies operator checks that an expression conforms to a type without replacing the inferred type of the expression. An annotation can widen the value and a type assertion only asks the compiler to trust the programmer.
Runtime and configuration
  • Utility types transform existing types. Partial makes its properties optional, Required does the opposite, Pick and Omit select keys, and Record models a key-to-value map.
  • A type guard narrows a type within a branch. typeof, instanceof, the in operator, value is T predicates and assertion functions allow you to show the compiler which variant exists at runtime.
  • Optional chaining (?.) cuts a chain only before null or undefined. Nullish coalescing (??) uses the alternative value only for those two cases, while || also replaces 0, false, and the empty string.
  • Decorators receive metadata about classes or members and can replace or complement their definition depending on the proposal and configuration used. Angular uses them to register components, directives, pipes and injectables.
  • The strict setting enables a set of checks, including nullability, function parameters, and initialized properties. The compiler finds invalid states before they reach the template or runtime.

Example

type LoadState<T> =
  | { kind: 'idle' }
  | { kind: 'loading' }
  | { kind: 'success'; data: T }
  | { kind: 'error'; error: Error };

function assertNever(value: never): never {
  throw new Error(`Unhandled state: ${JSON.stringify(value)}`);
}

Questions and answers

Why does unknown outperform any?See answer

unknown forces you to validate or narrow the type before using it. any allows invalid operations and propagates holes throughout the application.

interface or type?See answer

Both describe shapes of objects. interface supports declaration merging and contract-oriented extension; type also represents unions, intersections, tuples, and computed types. The consistency of the code and the capacity needed decide the choice.

What is the difference between satisfies and as?See answer

satisfies checks that the value satisfies a contract and preserves its inference. as forces an interpretation of the type and may hide an incompatibility. I use assertions only when the runtime provides a guarantee that the compiler cannot prove.

How do you design a useful generic?See answer

The generic must preserve a relationship between values, for example between input and output or between a key and its property. If the type parameter appears only once, perhaps a union or a specific type better communicates the contract.

Does TypeScript validate an HTTP response?See answer

No. Types disappear upon compilation and an assertion only changes what the compiler believes. I validate the JSON with a schema or type guard at the border and only then convert it to the internal model.

What does it mean for TypeScript to be structural?See answer

Compatibility depends on the form of the value. If an object has the required properties with compatible types, it can satisfy the contract even if it comes from another declaration. This facilitates composition, but requires caution with excessive properties and overly broad types.

How does a conditional type work with infer?See answer

A conditional type chooses a result according to a T extends U relationship. infer declares a type variable within the pattern: type Result<T> = T extends Promise<infer R> ? R : T extracts the resolved value of a Promise.

When would you use a mapped type?See answer

When one contract derives from another mechanically. type Flags<T> = { [K in keyof T]: boolean } preserves the keys and changes their values. This avoids duplicating models that later diverge.

How do you feel about this topic?

Block 02

Modern Angular

Components, reactivity, DI, RxJS, routing, forms and HTTP.

07

Angular: Basics, Rendering and Versions

Angular organizes the application as a tree of components, compiles templates, injects dependencies and updates the DOM using change detection. From that base, standalone, Signals, zoneless and migrations between versions are understood.

Theory

Model Angular
  • Angular is a framework for building web applications from a tree of components. Each component brings together a TypeScript class, a template, styles, and a host element. router, dependency injection, forms and HttpClient complete the platform.
  • bootstrapApplication creates the environment injector, instantiates the root component and connects its host view to DOM. From that root Angular cycles through views, evaluates bindings and updates only the properties of DOM whose value changed.
  • A template combines HTML with expressions and bindings. {{ value }} interpolates text, [property] writes a property, [attr.name] writes an attribute, (event) listens for an event, and [(value)] combines input and output under a two-way binding contract.
Templates and DOM update
  • Angular compiles the templates and knows in advance which nodes and bindings to create. Change detection re-evaluates those bindings when a notification flags a view for testing; Signals allow you to register precise reactive dependencies.
  • Angular releases major core and CLI versions in an aligned manner. Each version supports specific ranges of Node.js, TypeScript, and RxJS; ng version, the compatibility table and the Update Guide allow you to check them before a migration.
  • New applications use standalone components. NgModules are still relevant in older databases and libraries, but should no longer drive a new design for no reason.
Modern Angular
  • Angular 21+ uses change detection zoneless by default. The code must report changes using signals, listeners, AsyncPipe, setInput, or markForCheck.
  • Modern control flow uses @if, @for, @switch and @empty. track needs a stable identity; using index on mutable lists creates visual bugs and DOM job.
Versions and migrations
  • @defer separates the dependencies of a view in another chunk and loads them using triggers such as viewport, idle or interaction. LCP and CLS show whether deferring visible content worsens main loading or causes layout breaks.
  • Adoption of a new API depends on its stability, support, team capacity, and fallback cost. APIs such as resource, httpResource or Signal Forms require their status to be reviewed before being incorporated into a production base.

Example

bootstrapApplication(AppComponent, {
  providers: [provideRouter(routes), provideHttpClient()],
});

@Component({
  selector: 'app-root',
  template: `
    <button [disabled]="saving()" (click)="save()">
      {{ saving() ? 'Guardando…' : 'Guardar' }}
    </button>
  `,
})
export class AppComponent {
  saving = signal(false);
}

Questions and answers

Would you migrate everything to the latest version?See answer

I would migrate by supported increments, with tests, bundle budgets and observability. I prioritize security, compatibility and deprecated APIs; then I adopt new syntax.

Does Standalone remove modules?See answer

Eliminates the need for NgModules to declare components. Modules can still bundle legacy APIs or libraries. Standalone simplifies dependencies and lazy loading.

What would you check before activating zoneless?See answer

I look for mutations that depend on ZoneJS, libraries that update fields without notifying and direct uses of external APIs. I migrate the visible state to signals, AsyncPipe or explicit flags and compare tests and metrics before removing ZoneJS.

How do you decide what content to upload with @defer?See answer

I differentiate expensive content that does not participate in the first visual objective. I choose trigger and prefetch based on the probability of use, reserve space to avoid CLS and measure LCP, transfer and interaction in a production build.

What happens from bootstrapApplication until seeing the first component?See answer

Angular creates the environment injector with the application providers, instantiates the root component, creates its host view and executes the first render. The compiled template creates nodes, evaluates bindings, and connects listeners before subsequent changes go into change detection.

Interpolation, property binding or attribute binding?See answer

Interpolation produces text. Property binding writes a runtime property of the element or component. Attribute binding writes the attribute, for example ARIA or SVG. I choose based on the actual destination of the value, not based on a syntax preference.

How does Angular update DOM?See answer

The compiled template contains instructions for each binding. During change detection Angular evaluates the expression, compares the result with the previous value and writes only the destination that changed. It does not rebuild the entire HTML component.

What would you adopt first when modernizing an old application?See answer

I update supported majors and stabilize tests. Then I reduce NgModules with standalone, migrate control flow and just introduce Signals or zoneless where the state model justifies it. Each stage preserves a way of measuring and reversing.

How do you feel about this topic?

08

Components, templates and composition

A Senior component maintains a small API, explicit local state, and a readable template. Composition beats inheritance for UI reuse.

Theory

Component contract
  • Each component renders within a host element. The host metadata property declares host classes, attributes, properties, and listeners in one place; a consumer binding can collide with a component binding and Angular resolves the priority depending on whether it is static or dynamic.
  • @let declares a local value that Angular keeps up to date. A template reference variable such as #input references an element, component, exported directive, or TemplateRef, and only exists within the scope of the view where it was declared.
  • ng-container groups bindings without creating a DOM node. ng-template declares a fragment that does not render itself; Angular represents it with TemplateRef and you can instantiate it using NgTemplateOutlet or ViewContainerRef.createEmbeddedView.
Templates and fragments
  • NgComponentOutlet and ViewContainerRef.createComponent create known components in runtime. The inputBinding, outputBinding and twoWayBinding helpers connect their API when they are created and avoid scattered manual assignments or subscriptions.
  • The metadata of a component connects a class with its selector, template, styles, encapsulation strategy, change detection, imports and providers. Host bindings apply properties, attributes or listeners to the host element of the component.
  • input() declares an input signal and output() creates an emitter typed towards the parent. model() combines an input with its output nombreChange, which enables two-way binding for controls whose value is part of their public contract.
Composition and dynamic rendering
  • Projection with ng-content defines static slots. TemplateRef, ng-template, ViewContainerRef and dynamic creation cover advanced composition.
  • viewChild and viewChildren query the self view; contentChild and contentChildren query projected content. Queries based on signals change when the tree changes. A required query fails if the contract does not find the expected child.
Template performance
  • A directive adds behavior; a component adds behavior and view. A pure pipe should transform without effects and return the same result for the same inputs.
  • Angular can evaluate a template expression during each view check. An expensive function called from the template repeats that work. computed memorizes a derivation and only recalculates it when one of the signals read changes.

Example

@Component({
  selector: 'user-picker',
  host: { '[class.disabled]': 'disabled()' },
  template: `
    @let selected = selectedUser();
    <button #trigger (click)="open.set(true)">{{ selected?.name ?? 'Elegir' }}</button>
    <ng-template #row let-user>
      <button (click)="select(user)">{{ user.name }}</button>
    </ng-template>
  `,
})
export class UserPicker {
  disabled = input(false);
  selectedUser = model<User | null>(null);
  open = signal(false);
}

Questions and answers

Input or state service?See answer

An input expresses dependency on the parent and keeps the component reusable. A service serves state shared by distant branches or a domain. Do not hide presentation data by globalizing everything.

Content projection or input TemplateRef?See answer

ng-content works for fixed slots and declarative ergonomics. TemplateRef allows you to repeat, parameterize, or choose templates at runtime.

What should be part of a component's public API?See answer

Only inputs, outputs and slots that represent real variations of the product. If an option exposes internal details or joins invalid states, I prefer to split responsibilities or model a more precise join.

When would you create a directive instead of a component?See answer

I create a directive when I need to add behavior to an existing element without imposing markup. I create a component when the unit has visual structure, state, and an API that must evolve together.

Property binding or attribute binding?See answer

A property binding writes to the runtime property of the element or component, for example [disabled]. An attribute binding writes the attribute HTML with [attr.aria-expanded]. I use attributes for ARIA, SVG or metadata without an equivalent DOM property.

What does a template reference variable represent?See answer

It depends on the node: in a native element it references the HTMLElement, in a component its instance, with exportAs a directive and on ng-template a TemplateRef. Its scope belongs to the view that declares it.

Why doesn't ng-template appear in DOM?See answer

Declare a view recipe. Angular only creates its nodes when a directive, NgTemplateOutlet or ViewContainerRef instantiates its TemplateRef. This allows you to repeat the fragment and pass context to it.

How would you create a dynamic component with bindings?See answer

I use ViewContainerRef.createComponent if it must be part of that view and pass bindings with inputBinding, outputBinding or twoWayBinding. For a declarative case I can use NgComponentOutlet; for lazy loading visual I prefer to evaluate @defer.

How do you feel about this topic?

09

Lifecycle and render hooks

Order matters when a component coordinates inputs, queries, DOM and external resources.

Theory

mental model
  • Angular creates an instance, assigns inputs, runs the first change detection, initializes content and view, and then repeats the check hooks on each traversal. Each hook corresponds to a specific point in that process and does not work as a generic event.
  • Render hooks are not executed during SSR. afterNextRender serves for an operation DOM after the next render and afterEveryRender for an integration that must accompany successive renders; both require cleanup if they create persistent resources.
  • The builder sets up dependencies and cheap state. ngOnInit uses initialized inputs. ngOnChanges reacts to input changes and runs before ngOnInit on the first pass.
Operation and APIs
  • ngAfterContentInit/Checked relate to projected content. ngAfterViewInit/Checked are related to the view itself and queries.
  • afterNextRender executes a callback after the next complete render; afterEveryRender does it after each render. Grouping DOM writes before geometric reads avoids alternating style recalculation and forced layout.
Decisions, risks and verification
  • DestroyRef registers cleanup in the same context where a resource is born. takeUntilDestroyed completes a subscription when that context is destroyed. Observers, timers and listeners created outside of Angular also require their explicit cleanup function.
  • ExpressionChangedAfterItHasBeenCheckedError appears in development when an expression changes after Angular has already checked that view within the same loop. The cause is usually a data flow that writes to an ancestor or modifies state during a late hook; deferring with a timer hides the inconsistency.

Questions and answers

Builder or ngOnInit?See answer

The constructor belongs to TypeScript and DI. ngOnInit belongs to the Angular loop and receives ready inputs. Avoid I/O on both if a resolver, store or resource expresses the load better.

How do you avoid leaks?See answer

Use AsyncPipe, signals or takeUntilDestroyed; clean external APIs with DestroyRef.onDestroy. Then I verify repeated navigation with profiler and tests.

ngAfterViewInit or afterNextRender to measure DOM?See answer

ngAfterViewInit confirms that Angular initialized the view, but a measurement may depend on a later render. afterNextRender executes work after the next render of the tree and allows separating write and read phases.

What advantage does DestroyRef provide?See answer

Place the cleanup next to the resource that needs it and avoid concentrating contextless teardown on ngOnDestroy. I use it with listeners, observers and takeUntilDestroyed to bind their life to the injection context.

In what order does the first initialization run?See answer

Angular assigns inputs, executes ngOnChanges, ngOnInit, content hooks, view hooks and completes the render. The Checked hooks run again on subsequent traversals; Init run once.

Does afterNextRender work during SSR?See answer

No. Render callbacks are browser dependent. I use them to measure or integrate DOM after rendering and keep the SSR path free of that API.

When would you use ngOnChanges vs computed?See answer

ngOnChanges is useful when I need to compare input changes or execute an imperative adaptation. A computed best expresses a pure derivation of signal inputs because it maintains the relationship without manual synchronization.

Why can a setTimeout hide an ExpressionChanged?See answer

Moves the mutation to another task and avoids the current check, but preserves a misplaced data stream. I correct who owns the state or move the job to the appropriate hook and phase.

How do you feel about this topic?

10

Change detection, Signals and zoneless

This section usually separates recent experience from inherited knowledge. Explain who notifies Angular, which view becomes dirty, and when a derivation is recalculated.

Theory

Tour and notifications
  • Change detection runs through the views that Angular considers necessary, evaluates their bindings and compares the result with the previous value. A notification marks a view and its ancestors so that the next traversal includes that branch.
  • OnPush can skip a clean subtree. An input with a new reference, an event handled in the view, a reading of signal that changes, AsyncPipe, setInput or markForCheck flag work again.
  • linkedSignal maintains an editable state that resets or adapts when a dependency changes. resource and httpResource model reactive asynchronous loading; Its convenience is no substitute for an explicit cache, invalidation, and error policy.
Signals and derived state
  • Default checks a subtree more frequently. OnPush allows skipping subtrees when they do not receive new inputs or notifications.
  • A writable signal uses set or update; computed derives state, memorizes and tracks dynamic dependencies; effect connects reactive state with a non-reactive API.
  • computed represents derived state: it reads other signals, memorizes the result and remains free of effects. effect executes an operation when its dependencies change. Copying a derivation using effect creates two sources of truth and can cause redundant cycles or writes.
OnPush and zoneless
  • Signals compare by Object.is except equality function. A deep mutation preserves the reference and can hide the change.
  • untracked reads a signal without registering a dependency. Use it when reading is incidental, not to cover up a poorly designed graph.
Diagnostics and performance
  • Zoneless reduces unnecessary patches and checks. Requires updates to arrive via APIs that notify Angular.
  • Signals and RxJS complement each other: signals for synchronous state read by the view; RxJS for asynchronous streams, cancellation, concurrency, and events.

Example

private readonly query = signal('');
readonly normalizedQuery = computed(() => this.query().trim().toLowerCase());
readonly results = computed(() =>
  this.items().filter(x => x.name.toLowerCase().includes(this.normalizedQuery()))
);

Questions and answers

Does OnPush make the app immutable?See answer

No. OnPush changes when Angular checks the view. Immutability makes it easier to detect changes by reference and avoids corrupt shared state.

When to use effect?See answer

For logging, storage, canvas, browser APIs or external integration. UI derivations belong to computed.

What breaks when removing ZoneJS?See answer

Code that mutates fields without issuing a supported notification, as well as dependencies on NgZone events. I would migrate state to signals or flag the view.

Why might a deep mutation not update the view?See answer

A signal compares the new value with the old one using Object.is by default. Mutating a property preserves the reference and does not publish another value. I create a new reference or model field as a separate signal.

How do you choose between computed and effect?See answer

computed calculates derived state and only depends on other signals. effect synchronizes the reactive graph with an external boundary such as storage, logging, or canvas. I do not copy derived state through effects.

What marks a OnPush view as dirty?See answer

A new reference in an input, an event handled within the view, a signal read by the changing template, AsyncPipe, setInput or markForCheck. An internal mutation of an object without notification preserves the same reference and may leave the UI old.

markForCheck or detectChanges?See answer

markForCheck schedules the view for the next tour and maintains the normal flow. detectChanges runs an immediate check of that view and its children; I reserve it for controlled integrations because it can introduce unexpected work and order.

What does linkedSignal solve?See answer

Models an editable state that depends on another signal and needs to be readjusted when that source changes, such as a selection that must remain valid when replacing the list. Avoid an effect dedicated to copying and correcting state.

How do you research too many renders?See answer

I record an interaction with Angular DevTools and the Performance panel, identify which notification marked the branch, and review references, template functions, and effects. I change a cause and measure scripting and INP again.

How do you feel about this topic?

11

Dependency Injection in depth

Angular resolves dependencies in hierarchies. The location of the provider defines lifetime, visibility and isolation.

Theory

mental model
  • Dependency Injection separates the creation of a dependency from its consumption. Angular looks for a provider for a token, runs its factory when appropriate, and maintains the instance based on the injector that owns it.
  • Resolution starts at the injector associated with the current node or environment and moves up the hierarchy. A component provider creates one instance per subtree; one on the road lives with that lazy environment; providedIn: 'root' shares the instance in the application.
  • useClass, useValue, useFactory and useExisting express different ways of producing a token. Multi providers accumulate several values ​​under the same token and are used for extensible pipelines.
Operation and APIs
  • providedIn: 'root' creates a singleton per root EnvironmentInjector and allows tree shaking. A component provider creates one instance per component.
  • The resolver looks for ElementInjectors first and then EnvironmentInjectors. Lazy routes can create separate contexts and instances.
  • useClass creates a class for a token; useValue returns an existing value; useExisting creates an alias; useFactory calculates the dependency on other injections. Multi providers accumulate several values ​​under a token and InjectionToken represents contracts that do not exist as a class in runtime.
Decisions, risks and verification
  • providers is visible to view and descendant content; viewProviders hides the provider from the projected content.
  • self, skipSelf, host and optional limit the search. Use them for intentional contracts, not as a patch.
  • inject() needs injection context: initializer, DI-managed constructor, factory, or runInInjectionContext.

Example

export const ANALYTICS = new InjectionToken<Analytics>('analytics');

export const appConfig: ApplicationConfig = {
  providers: [
    { provide: ANALYTICS, useClass: BrowserAnalytics },
    { provide: HTTP_INTERCEPTORS, useClass: AuditInterceptor, multi: true },
  ],
};

Questions and answers

Is a Angular service always singleton?See answer

It is a singleton within the injector that provides it. Two injectors can create two instances. The phrase 'singleton global' omits the scope.

Why use InjectionToken?See answer

Allows you to inject deleted configuration, functions or interfaces into runtime. The token preserves identity and can define factory and type.

What is the difference between useClass and useExisting?See answer

useClass asks the injector to construct another instance of the indicated class. useExisting creates an alias to a registered instance. I use aliasing when two tokens must share identity and state.

How does the location of the provider affect a feature?See answer

The injector that registers the provider defines its scope and lifetime. A component provider isolates instances per subtree; one route can live with the lazy feature; root shares the instance in the application.

How does Angular search for a provider?See answer

It starts at the injector of the current context, queries the node's providers and environment, and works its way up until it finds the token. Resolution modifiers change that path; if no provider exists and is not optional, Angular throws an error.

Component or route provider?See answer

The component provider creates an instance associated with that subtree and is destroyed with it. The route provider shares state between lazy feature components and lives with its environment injector.

What is a multi provider for?See answer

It allows multiple parties to register values under the same token and for the consumer to receive an array. I use it for plugins, validators or extensible pipelines where each feature provides an implementation.

How risky is providedIn: 'root'?See answer

Converts the service to an application singleton. If you save screen or user state without a reset policy, you can mix navigation cycles and sessions. The scope must match the useful life of the data.

How do you feel about this topic?

12

RxJS and concurrency

The Senior interview usually involves searches, saving, polling or concurrent events. I chose the operator based on the concurrency policy.

Theory

Contract Observable
  • A subscription represents the execution and its teardown. complete and error close the contract; unsubscribe terminates it from the consumer. The producer must register cleanup to release timers, listeners, sockets or cancelable requests.
  • The location of catchError changes the scope of the fault. Within a flattening operator it recovers an internal operation and keeps the source alive; outside terminates or replaces the entire flow.
  • shareReplay shares a subscription and preserves broadcasts for late subscribers. Before using it as a cache, you must decide buffer size, refCount, reset, errors, useful life and isolation per user.
Operators and attendance
  • Cold observables create the producer by subscription; hot observables share an external producer. share and shareReplay change that relationship.
  • switchMap cancels the previous inner; It is used for search. concatMap serialize; serves to preserve order. mergeMap allows concurrency. exhaustMap ignores triggers while one is active.
  • map transforms values; tap runs effects; filter decides emissions; scan accumulate; catchError defines the error limit.
Bugs and teardown
  • The location of catchError defines which stream ends. Within switchMap or another flattening operator, the error is replaced only for that request and the outside stream can continue listening. Outside the operator, the error terminates the entire string unless another observable is returned.
  • combineLatest reacts to latest values; forkJoin expects everyone to complete; withLatestFrom takes context when the source emits.
Sharing and cache
  • Subject does not keep a value, BehaviorSubject keeps the last one and requires an initial one, and ReplaySubject plays a number or window of emissions. Exposing only asObservable() prevents external consumers from writing to the producer state.
  • shareReplay({bufferSize: 1, refCount: true}) can cache, but you need invalidation, error handling, and lifetime semantics.

Example

results$ = this.query.valueChanges.pipe(
  debounceTime(250),
  distinctUntilChanged(),
  switchMap(query => this.api.search(query).pipe(
    catchError(error => of({ items: [], error }))
  )),
  shareReplay({ bufferSize: 1, refCount: true })
);

Questions and answers

Why not subscribe within subscribe?See answer

It nests life cycles and errors, complicates cancellation and creates races. A flattening operator expresses the policy and returns a single subscription.

How do you cancel a previous search?See answer

I debounce, remove duplicates and use switchMap. unsubscribe cancels the XHR/fetch request when the backend and client allow it.

Does switchMap cancel job on server?See answer

Unsubscribe stops the observation and may abort the request if the source integrates cancellation, such as HttpClient. The server may have started the job. Effects operations require idempotence or their own cancellation protocol.

How risky is shareReplay?See answer

You can retain the last value and keep the subscription alive longer than expected. I define buffer, refCount and reset policy according to the life cycle. I also decide how to invalidate errors and stale data.

Where do you put catchError inside switchMap?See answer

Inside if each request can fail and the source must continue listening for lookups. Out if any error terminates or replaces the entire flow. The position determines which subscription is closed.

What should teardown a Observable do?See answer

Stops the resource created by that subscription: removes listeners, clears timers, closes sockets or aborts compatible I/O. It must also tolerate repeated calls without producing invalid effects.

When can shareReplay(1) produce a leak?See answer

When you keep the source subscribed after the last consumer leaves or keep a heavy value without a reset policy. I configure refCount and resets depending on whether I need a persistent cache or just sharing concurrent consumers.

How to choose between the four flattening operators?See answer

I choose the concurrency policy: switchMap replaces, concatMap enqueues, mergeMap allows parallelism, and exhaustMap ignores new entries while one is still active. The semantics of the business decide which loss or order is valid.

How do you feel about this topic?

13

Status: local, services, Signals and NgRx

There is no single tool. A Senior reduces the scope of the state and increases the structure when complexity demands it.

Theory

mental model
  • The status belongs to the closest owner who needs to write it. A component resolves ephemeral state; a feature service coordinates several views; A store formalizes events and effects when many parties modify the same domain.
  • Source state and derived state must be separated. Signals computed and selectors compute views of the same data; Copying the result to another variable requires synchronization and allows inconsistencies.
  • Component local state: Ephemeral UI. Feature service: coordination of a branch. Global store: shared data, complex flows, auditing or development tools.
Operation and APIs
  • Server state is a local copy of remote data and requires caching, stale time, invalidation, deduplication, and retries. Client state is born in the interface, as selection, filters or a wizard, and its life cycle depends on the navigation and the scope of the feature.
  • In NgRx, an action describes an event, a reducer computes the next state without effects, a selector derives and memorizes queries, and an effect connects events to I/O. Entity normalizes collections as a dictionary of ids plus an ordered list.
  • The derived state is calculated from the source using selectors or computed; Storing it separately requires synchronizing copies. Actions expressed as domain events, for example invoiceSubmitted, allow various effects to react without being attached to the button that caused the event.
Decisions, risks and verification
  • ComponentStore and SignalStore encapsulate state of a feature without creating a global store. The choice depends on the stability of the API, the available ecosystem, and the team's experience with the reactive model.
  • An optimistic update modifies the UI before receiving confirmation. The design needs rollback or reconciliation when it fails, an idempotent key to avoid duplicates, and a rule for conflicts between the local and remote versions.

Questions and answers

When to choose NgRx?See answer

When several flows share state, you need traceability, coordinated effects or complex rules. For an isolated form, a global store increases cost without benefit.

What would you never keep in the store?See answer

Recalculatable derivations, unnecessarily non-serializable objects, and ephemeral DOM state. I would save the minimal source of truth.

How do you separate server state from client state?See answer

Server state is a copy of remote data and requires stale time, caching, and invalidation. Client state is born in the interaction, for example filters or steps of a wizard. Separating them prevents a store from treating both lifecycles with the same policy.

What signals justify introducing NgRx?See answer

I consider it when multiple flows write the same domain, I need event traceability, coordinated effects or shared update rules. A local form or isolated display does not justify that cost alone.

When does a service with Signals stop reaching?See answer

When multiple features write to the same domain, I need clear event history, coordinated effects, inspection tools, or consistent update rules. At that point a formal store reduces implicit paths.

What is derived state?See answer

It is a value that can be calculated from the source state, like the total of a cart. I express it with computed or a selector and don't save it separately, because two copies can diverge.

How do you model an optimistic update?See answer

I apply a local change with an operation ID, send the request, and commit or rollback depending on the result. I resolve concurrency, duplicates and error messages without losing a later edit.

What would you put in the global store?See answer

Shared domain state whose life crosses paths and requires coordination. Focus, accordion, or temporary form states remain close to the component unless another part of the application needs to control them.

How do you feel about this topic?

14

Routing and navigation

The router defines upload, authorization and data boundaries. Design routes as part of the architecture.

Theory

mental model
  • Router compares the URL with a route tree, executes redirects, guards and resolvers, activates components in outlets and preserves snapshots plus change streams. Navigation can be canceled or redirected before the view is created.
  • loadComponent and loadChildren create lazy borders. The providers declared in a route belong to its environment injector and allow services to be isolated by feature.
  • Component input binding can bring params, query params, static data, and resolvers to component inputs. That API reduces manual subscriptions, but the name and absence of each value is still part of the route contract.
Operation and APIs
  • loadComponent and loadChildren create lazy loading borders that download a feature when browsing. A small chunk per component increases requests and overhead; A product capacity frontier usually balances initial loading and reuse.
  • Guards control navigation on the client; The server must repeat authorization. CanMatch avoids selecting routes; CanActivate decides activation.
  • Resolvers reduce intermediate states when the route needs data before displaying. For load-tolerant displays, a load within the feature improves perception.
Decisions, risks and verification
  • Path params identify resources within the path; query params represent filters or shareable state; the fragment points to a section of the document. Child routes make up layouts, outlets show parallel trees, redirects normalize URLs and route data provides static metadata.
  • A RouteReuseStrategy can preserve the instance and the DOM of a route when navigating. It also preserves memory, state and subscriptions; an invalidation policy decides when to destroy that snapshot.
  • RouterTestingHarness creates a test router, navigates by URL, and exposes the activated component. Allows checking for invalid parameters, redirects, rejected guards and resolving errors from the observable behavior.

Example

export const routes: Routes = [{
  path: 'users/:id',
  loadComponent: () => import('./user.page').then(m => m.UserPage),
  canActivate: [authGuard],
  resolve: { user: userResolver },
  providers: [UserFeatureStore],
}];

Theme sources

Questions and answers

Does Guard equal security?See answer

No. A user controls the client. The guard improves UX and prevents accidental navigation; the API authorizes each operation.

Resolve or load into component?See answer

Resolve when the view does not make sense without the data or you need consistency before activating. Component loading for streaming, skeletons or partial content.

What is the difference between CanMatch and CanActivate?See answer

CanMatch decides if a route configuration can participate in matching and allows another route to be tested. CanActivate acts after choosing it and decides whether to activate it. None replace server authorization.

When would you avoid a resolve?See answer

I avoid blocking navigation for secondary or slow data. The screen can show structure, loading and partial recovery. I use resolve when the data defines whether the route makes sense or when entering without it would produce an invalid state.

In what order do guards and resolvers intervene?See answer

Angular recognizes the path, evaluates guards and, if allowed to continue, executes resolvers before activating the component. A redirect or cancellation cuts off navigation; Errors need a navigation policy or error handler.

Does a guard protect data?See answer

No. Control customer navigation and improve the experience. The API must authenticate and authorize each operation because a user can call the endpoint without going through the Router.

When would you use a resolver?See answer

When the route doesn't make sense without a small, critical piece of information or I need to decide before activating it. For secondary content I prefer to load inside the view and show partial states, because a long resolve delays all navigation.

How do you test the Router?See answer

I use RouterTestingHarness with real routes, navigate a URL and check component, redirects and visible status. Isolated tests cover the logic of guards or resolvers and integration tests cover the navigation order.

How do you feel about this topic?

15

Complex forms

Senior forms include typing, composition, asynchronous validation, accessibility, and performance.

Theory

mental model
  • Reactive Forms creates a tree of controls in TypeScript. Each control retains value, validation, interaction, and disabled status; the group adds the states of its children and emits when the model changes.
  • updateOn: 'blur' or 'submit' reduces validations and requests during writing. A group validator compares related fields and returns the error at the level that owns the rule.
  • An asynchronous validator must complete and resolve races. Debounce, switchMap and a short cache avoid unnecessary requests; the UI distinguishes PENDING, network error and invalid value.
  • Reactive Forms models the form in TypeScript; template-driven is for small cases. Typed Forms reduce casts and errors.
Operation and APIs
  • FormControl, FormGroup, FormArray and FormRecord cover fixed forms, lists and dynamic keys.
  • A synchronous validator returns ValidationErrors | null; an asynchronous one returns Promise or Observable and needs cancellation or debounce depending on the case.
  • ControlValueAccessor connects your own control to Angular Forms using four operations: writing a value, recording changes, recording touched, and applying disabled. The control should not re-emit the value that Forms just wrote to it as a change, because that creates a loop.
Decisions, risks and verification
  • Copying each utterance of valueChanges to another object creates two representations of the form that can diverge. The FormGroup can be the source of truth during editing and the submit can map its value to a command or DTO.
  • Errors are displayed after interaction or submit to avoid noise before the user acts. aria-describedby associates the message with the control; focus should reach the first invalid field when a submit cannot continue.
  • Signal Forms offers a new model in recent versions. Present it as an option to evaluate, not as an automatic replacement for Reactive Forms.

Example

readonly form = new FormGroup({
  email: new FormControl('', {
    nonNullable: true,
    validators: [Validators.required, Validators.email],
    asyncValidators: [uniqueEmailValidator(this.http)],
    updateOn: 'blur',
  }),
  addresses: new FormArray<FormGroup<AddressControls>>([]),
});

Theme sources

Questions and answers

How would you design 60 dynamic forms?See answer

I define a typed schema, components by field type, derived visibility rules and registrable validators. I separate data, layout and behavior; I test the engine with contract cases.

What's wrong with a CVA?See answer

Issue during writeValue, forget disabled state or do not check touched. That creates loops and breaks the semantics of the form.

What contract must a ControlValueAccessor fulfill?See answer

You must write the external value without issuing a user change, register change and touched callbacks, and honor the disabled state. You also need a clear representation for null and partial values.

How do you avoid races in asynchronous validation?See answer

I model validation as a flow that cancels the previous query upon changing the value. I apply debounce when appropriate and distinguish transport error, invalid value and pending status on the interface.

Where would you place a validation between two fields?See answer

In the FormGroup that owns both controls. The validator returns an error from the group and the presentation decides in which fields to announce it without mutating foreign errors.

What changes with updateOn: 'blur'?See answer

The control updates value and validation when it loses focus. It reduces work and requests while typing, but changes when valueChanges emits and when the UI can display the result.

How do you type a FormArray?See answer

I declare the type of the repeated control, for example FormArray<FormGroup<AddressControls>>. The type describes controls, while getRawValue produces the value including disabled controls.

How do you approach the first error when sending?See answer

I mark controls as touched, locate the first invalid element following the visual order, focus it, and connect the message with aria-describedby. An error summary can link each field in long forms.

How do you feel about this topic?

16

HTTP, APIs, errors and cache

The client must model contracts, cancellation and failures. Interceptors solve cross-cutting concerns, not domain logic.

Theory

mental model
  • HttpRequest and HttpHeaders are immutable. An interceptor uses request.clone to change URLs, headers, params or body and then passes the request to the next handler.
  • Functional interceptors are executed in the order of registration for the request and in reverse order for the response. HttpContextToken allows you to activate policies per request without converting them into network headers.
  • observe: 'events' exposes progress, headers and final response. The upload progress requires a backend to support it; fetch does not report upload progress in the same way as XHR.
  • provideHttpClient registers the HTTP client and functional interceptors form a chain around each request. Services or feature repositories encapsulate URLs, DTOs and access rules so that components depend on the domain.
Operation and APIs
  • TypeScript types disappear on compile and do not validate the received JSON. A schema runtime checks external data before using it; a mapper translates the server DTO into a stable internal model.
  • An interceptor can add authentication, correlation IDs and telemetry, or normalize errors. A global loader needs to count concurrent requests: a boolean is turned off when the first one finishes even if others are still active.
  • A retry repeats an operation that failed. Idempotent methods can be repeated without changing the result; a write needs an idempotence key if there is a risk of duplication. Backoff, jitter, and a limit prevent amplifying a crash, and 4xx functional errors require further action.
Decisions, risks and verification
  • Timeout, cancellation, offline, network failure, 401/403, 404, validation and 5xx represent different states. The interface can offer retry for network or timeout, login for 401, correction of fields for validation and a fallback for server errors.
  • httpResource connects HttpClient with a signals API for request, value, loading and error. On large domains, the strategy still requires caching keys, invalidation, per-user isolation, and coordination with other writes.
  • A cache is defined by its key, lifetime, invalidation policy, and isolation. Deduplication shares an ongoing petition; stale-while-revalidate returns the old value while updating. Including the user or tenant in the key avoids mixing private data.

Example

export const authInterceptor: HttpInterceptorFn = (request, next) => {
  const token = inject(AuthStore).token();
  const authenticated = request.clone({
    setHeaders: { Authorization: `Bearer ${token}` },
  });
  return next(authenticated);
};

Theme sources

Questions and answers

Where would you refresh a token?See answer

In an authentication layer coordinated by interceptor, with a single renewal in flight and controlled queue. I avoid loops and clean the session if the refresh fails.

How to type an HTTP response?See answer

The HttpClient generic expresses the expectation, it does not validate the server. At a critical boundary I validate and transform the DTO before exposing it.

Why does the order of interceptors matter?See answer

Each interceptor envelops the next. The request proceeds in the recorded order and the response returns in reverse order. Authentication, retry, cache and logging can change their behavior depending on that composition.

How do you invalidate a cache after a mutation?See answer

I relate each writing to the affected keys. I can override, update optimistically, or replace with the server's response. The policy includes rollback and avoids deleting data from unrelated domains.

Why is a HttpClient request cloned?See answer

HttpRequest is immutable. clone creates a request with the changes and preserves the original object so that the interceptor chain can reason without shared mutations.

What order do the interceptors run in?See answer

The request traverses the list in the order of registration. The response returns down the chain in reverse order, as nested layers. The order affects auth, cache, retry, loaders and telemetry.

What is HttpContext for?See answer

Transports local configuration within the pipeline without sending it to the server. An interceptor can read an HttpContextToken to bypass auth, activate caching, or change error handling for a specific request.

How do you avoid two simultaneous token refreshes?See answer

I share a single refresh operation while it is active, queue or retry the original requests after the new token and clear the state when finished. If the refresh fails, I log out only once.

How do you feel about this topic?

Block 03

Platform and architecture

Browser internals, DOM, networking, boundaries, patterns, SOLID and code evolution.

17

Browser internals, DOM, storage and network

Angular runs on the web platform. A Senior understands the cost of DOM, layout, storage, navigation and protocols.

Theory

Basics
  • DOM represents the document; BOM groups browser APIs such as window, history, location, navigator and screen. Angular abstracts part of DOM, but does not replace the platform.
  • Selection: querySelector, querySelectorAll, getElementById. Events go through capture, target and bubble. Delegation takes advantage of bubbling to handle dynamic lists.
  • preventDefault avoids the default action; stopPropagation stops propagation. Using them without understanding semantics breaks forms, links and accessibility.
  • The browser parses HTML and CSS, builds DOM and CSSOM, calculates styles and layout, paints and composes layers. Reading layout after writing styles can force reflow.
Mechanism and application
  • localStorage persists by origin and offers synchronous API; sessionStorage lives by tab; IndexedDB stores structured data asynchronously. Cookies travel according to their attributes and request rules.
  • Same-origin combines scheme, host and port. CORS allows a server to authorize cross-origin reads; The OPTIONS preflight validates certain methods and headers.
  • HTTP cache uses Cache-Control, validators such as ETag and keys that may vary. Service Worker can intercept requests and adds another layer of caching and invalidation.
Decisions and limits
  • DNS resolves host; TLS authenticates and encrypts; HTTP transports requests. HTTP/2 multiplexes streams; HTTP/3 uses QUIC over UDP.
  • SPA updates views without reloading document. History API maintains URLs; the server must redirect app paths to HTML or render them.
  • Web Worker executes JavaScript outside the main thread and communicates via messages. Does not access DOM. Service Worker operates as a separate loop and network proxy.

Questions and answers

DOM and BOM?See answer

DOM models the document. BOM brings together objects and APIs from the browser environment, such as history, location, and navigator.

localStorage, sessionStorage or IndexedDB?See answer

I choose localStorage for few non-responsive preferences, sessionStorage for tab life and IndexedDB for volume, queries and asynchronous work.

What is CORS?See answer

A browser policy that allows the server to declare which origins can read a response. It does not protect endpoints from non-browser clients nor does it replace authorization.

Reflow and repaint?See answer

Layout recalculates geometry; paint generates pixels; compositing combines layers. Changes and interleaved reads can force synchronous work.

What does a forced synchronous layout produce?See answer

A write invalidates styles or layout and a subsequent geometric read, such as getBoundingClientRect, forces the browser to calculate the result at that time. I group reads and writes to avoid repeating that work within a loop.

Does CORS protect an API against unauthorized clients?See answer

No. CORS controls which responses JavaScript can read from another origin in a browser. A server script can call the endpoint. The API still needs authentication, authorization and validation.

How do you feel about this topic?

18

Angular Application Architecture

A useful architecture reduces coupling and makes domain boundaries visible.

Theory

Basics
  • The organization by feature groups UI, data access, models and routes that change for the same product capacity. A global organization by technical type disperses a modification across distant folders and weakens domain boundaries.
  • A presentational component receives data and emits events; an orchestrator coordinates state, navigation, and services. Separation reduces dependencies when multiple views reuse the presentation, but adds empty layers if both pieces always change together.
  • Dependency inversion makes the domain depend on a stable contract and the detail implements that contract. In Angular, a InjectionToken plus an adapter allows changing analytics, storage, payments or an external API without modifying consumers.
Mechanism and application
  • The public API of a library or feature declares which symbols other modules can consume. Deep imports cross that boundary, dock to the internal file tree, and turn a local refactor into a global change.
  • A monorepo improves sharing and coordinated refactors; adds tooling and ownership cost. Nx can enforce boundaries and cache tasks.
Decisions and limits
  • Micro-frontends serve for independent deployment and ownership. They increase duplication, integration, observability and visual consistency.
  • An Architecture Decision Record preserves the context, the alternatives evaluated, the decision, its consequences, and a review date. The log explains why a restriction exists when the original team or context changes.

Questions and answers

Clean Architecture in frontend?See answer

I use their limits and dependency inversion where they protect business rules. I avoid copying backend layers if they only add files and mappings.

When to extract a library?See answer

When there is a stable contract and more than one real consumer, or when the limit requires ownership and own tests. Pull ahead freezes immature APIs.

How do you detect an incorrect feature boundary?See answer

Circular imports appear, coordinated changes between supposedly independent folders and shared services that know all domains. I relocate the behavior according to ownership and expose a small API per border.

What problem does a shared folder without rules cause?See answer

It receives components, models and services from different domains until it becomes a global dependency. I separate reusable primitives from business contracts and leave each model close to the feature that owns it.

How do you prevent one feature from depending on details of another?See answer

I expose a small public API and domain contracts. The consuming feature does not import internal components, private stores, or deep file paths; communicates through published services, events or models.

When does a facade layer add value?See answer

When you concentrate several stores or services, you translate models and offer stable use cases to the UI. If you just forward each method with the same name and type, you add navigation without reducing coupling.

How do you feel about this topic?

19

Patterns, SOLID and design quality

Patterns name recurring solutions. A Senior interview expects context and cost, not a memorized list.

Theory

Basics
  • Strategy for interchangeable policies; Adapter to integrate external contracts; Facade to reduce surface area; Factory for variable construction.
  • Observer appears in RxJS; Decorator in metadata and interceptors; Command and event patterns appear in stores. Singleton depends on the injector.
Mechanism and application
  • SRP separates reasons for change. OCP favors extension by contracts. LSP requires valid substitution. ISP maintains small contracts. DIP inverts dependencies towards abstractions.
  • Composition over inheritance avoids rigid hierarchies. The directives, providers and content projection form composition mechanisms.
Decisions and limits
  • A god service accumulates reasons for change; a massive shared module creates implicit dependencies; barrel cycles hide cycles; boolean flags multiply states; Nested subscriptions lose concurrency control and the business logic in templates is repeated and difficult to test.

Questions and answers

How to implement Singleton?See answer

In Angular I provide the service on a shared injector. The guarantee is valid within that scope; local providers or multiple applications create other instances.

Facade over NgRx?See answer

You can stabilize the feature's API and hide store details. You can also hide capabilities and duplicate names. I use it when protecting a real boundary.

How do you apply Dependency Inversion in Angular?See answer

The consumer depends on a contract expressed by an abstract class or InjectionToken. The configuration connects that contract to an implementation. I can change the border in tests or by environment without showing details to the consumer.

When does a facade worsen the design?See answer

A facade that only renames each method adds navigation without reducing coupling. I use it when concentrating a use case, hiding coordination between dependencies, or protecting the UI from subsystem changes.

How would you apply Strategy in Angular?See answer

I define a contract for the operation, register implementations using DI and select the strategy by configuration or context. The consumer knows the capacity, while each algorithm maintains its own tests and dependencies.

What sign indicates that an abstraction arrived too soon?See answer

The interface has a single implementation, it replicates all its methods and changes along with the detail. I wait for concrete cases of variation and extract the boundary that those cases share.

How do you feel about this topic?

Block 04

Quality and operation

Performance, rendering, testing, security, CI/CD and observability.

20

Performance and Core Web Vitals

Optimizing without measuring trades complexity for intuition. A Senior identifies the metric, captures a profile and verifies the result.

Theory

Basics
  • LCP measures when the largest visible element appears, INP observes the latency of interactions, and CLS accumulates unexpected displacements. Bundle size, long tasks, memory and render frequency explain their causes. Lighthouse uses a synthetic environment; RUM registers real devices and networks.
  • Lazy routes and @defer remove JavaScript from the initial bundle. The benefit depends on chunk waterfall, preloading, prefetch and HTTP caching: too many small borders can trade initial bytes for network latency.
Mechanism and application
  • OnPush allows subtree jumping without notifications, signals marks precise consumers, and a stable track preserves nodes from a list. Virtual scroll limits the visible DOM; Paging also reduces transferred data and server work.
  • An impure pipe and an expensive template function can be executed on each check. Global listeners without cleanup retain views, dimensionless images cause CLS, and a large dependency increases parse, compile, and run in addition to transfer.
Decisions and limits
  • AOT, tree shaking, budgets and source-map analysis detect regressions. A small import can drag a large dependency.
  • DOM writes invalidate styles and geometric reads can force their calculation. Grouping both phases avoids layout thrashing. Debounce reduces high frequency events; A Web Worker offloads CPU when the cost of serializing messages is less than blocking the main thread.

Questions and answers

The app is slow, where do you start?See answer

I define slow interaction, reproduce with real data and record performance. I identify network, scripting, layout or memory; I change a cause and measure again.

Does trackBy still exist?See answer

In *ngFor yes. Modern control flow uses track. Both preserve DOM identity; an unstable key voids the benefit.

How do you start a performance investigation?See answer

I define an interaction and a metric, reproduce with a production build and capture a profile. Then I separate network, scripting, rendering and memory. I optimize the measured neck and compare again under the same conditions.

Does OnPush fix a long JavaScript task?See answer

No. OnPush may reduce view checks, but a function that occupies the main thread still blocks input and render. I split the job, reduce its complexity or move it to a Worker if the message cost allows it.

How would you investigate a high INP?See answer

I reproduce the interaction with Performance panel and RUM, locate long tasks and separate scripting, style, layout and paint. Then I reduce work from the critical path, split CPUs or limit renders and measure again on real devices.

When is virtual scroll not enough?See answer

Virtual scroll reduces DOM nodes, but does not reduce downloaded data, expensive filters, or entire model memory. With hundreds of thousands of rows I combine server-side pagination, remote queries and an accessible visible window.

How do you feel about this topic?

21

SSR, SSG, hydration and hybrid rendering

I chose route strategy. SEO, personalization, server cost and interaction time drive different decisions.

Theory

Basics
  • Hydration reuses the DOM produced by the server and connects the client views without rebuilding the page. The server's HTML and the client's first render should produce the same structure.
  • Date.now, Math.random, locale, private data and different conditions between server and browser can create mismatches. The server must transfer the deterministic data or the client must calculate it after hydrating.
  • Incremental hydration keeps @defer blocks dehydrated up to a hydrate on ... trigger. Event replay records previous interactions and plays them when the section can respond.
Mechanism and application
  • CSR simplifies private applications. SSG serves stable content. SSR serves fresh HTML and SEO. Hybrid combines strategies per route.
  • Hydration reuses the HTML from the server. The client must produce a compatible structure; Invalid DOM or direct manipulation breaks the process.
  • Incremental hydration activates sectors when needed and works with @defer. Event replay preserves interactions prior to hydration.
Decisions and limits
  • window, document, storage and other browser APIs do not exist during SSR. Platform checks, injectable tokens, and render hooks isolate that code so that the server can build the HTML without accessing the client environment.
  • Transfer cache reuses certain responses obtained during SSR on the client and avoids a second immediate request. The key and the generated HTML must isolate data on a per-user basis to prevent a private response from terminating in another session.
  • A placeholder with the same dimensions as the final content reserves space and reduces CLS. Above-the-fold content participates in LCP and typically loads first; child blocks support lazy loading or lazy hydration.

Example

bootstrapApplication(AppComponent, {
  providers: [provideClientHydration()],
});

// La estructura renderizada debe coincidir en servidor y cliente.
@defer (on viewport; hydrate on interaction) {
  <reviews-panel />
} @placeholder {
  <reviews-skeleton />
}

Questions and answers

Does SSR improve all performance?See answer

Improves HTML delivery and SEO, but adds server and hydration. TTFB or interaction can worsen if the backend and the bundle do not match.

What causes hydration mismatch?See answer

HTML different between server and client, non-deterministic dates or random, DOM manipulated before hydrating and invalid markup.

How do you choose rendering strategy per route?See answer

I use SSG for stable content, SSR for request-dependent HTML, and CSR for private areas where the shell contributes little to the server. I evaluate SEO, personalization, latency, cache and operational cost per route.

What causes a hydration mismatch?See answer

The client produces a different tree than the server's HTML due to non-deterministic data, browser access, or conditional markup. I share the initial state, isolate APIs from the browser and keep the structure stable until hydrated.

What produces a hydration mismatch?See answer

The server and the client's first render generate different structures. Dates, random, locale, early access to DOM or browser-only conditions are common causes. I transfer deterministic data and postpone browser effects until after hydrating.

What does event replay do?See answer

Captures interactions that occur on HTML SSR before Angular connects listeners and plays them upon completion of the corresponding hydration. Prevents an early click from appearing lost.

What is the difference between full and incremental hydration?See answer

Full hydration activates the full application. Incremental hydration preserves dehydrated @defer limits and activates them by triggers such as viewport or interaction, reducing initial JavaScript in exchange for more states and loading decisions.

Why would you avoid changing the tree with isPlatformBrowser?See answer

The condition may cause server and client to create different nodes during hydration. I keep the same structure and run only the browser integration after the render, or exclude an isolated case from hydration as a last resort.

How do you feel about this topic?

22

Testing and quality strategy

A Senior Suite protects behavior and contracts. Avoid tests that copy the implementation.

Theory

Basics
  • A useful test prepares state, executes a observable action, and checks the result. Vitest provides runner, assertions, spies and fake timers; TestBed adds the Angular injection, compilation and rendering environment.
  • Component harnesses encapsulate how a component operates and allow tests to use a stable API. RouterTestingHarness navigates real routes within the test and checks guards, params, resolvers and activated components.
  • Practical pyramid: many logic tests, components for DOM behavior, border integration and few E2Es of critical journeys.
Mechanism and application
  • Modern Angular documents Vitest together with TestBed. Existing databases can use Jasmine/Jest; Strategy matters more than syntax.
  • A component test interacts with the DOM through roles, labels and events, and checks the visible result. Private methods and internal structure are implementation details; affirming about them makes the test fragile in the face of refactors without behavioral change.
  • HttpTestingController intercepts requests from HttpClient and allows method, URL, body and headers to be asserted before responding with success or error. verify() finally checks that no request has been left pending.
Decisions and limits
  • RouterTestingHarness simplifies navigation. Component harnesses create stable test APIs for reusable UI.
  • Fake timers control the debounce clock, retry and delays without waiting for real time. Marble tests represent RxJS emissions on a virtual timeline and are useful when order and concurrency are part of the contract.
  • A mock replaces a boundary and allows the unit to be isolated, but too many mocks can describe an integration that no real vendor supports. Contract tests verify that DTOs, adapters and clients respect the same contract.

Example

it('shows the resolved user', async () => {
  const harness = await RouterTestingHarness.create('/users/7');
  const request = http.expectOne('/api/users/7');
  request.flush({ id: 7, name: 'Ada' });
  await harness.fixture.whenStable();
  expect(harness.routeNativeElement?.textContent).toContain('Ada');
});

Theme sources

Questions and answers

Which test would you write first?See answer

The most expensive risk: domain rule, permission, payment, migration or interaction that has already failed. Percentage coverage does not replace that prioritization.

Unit test of a component with a service?See answer

I replace the service border, execute the interaction with the DOM and check the visible result and the relevant call. I don't test Angular.

What do you test in a unit and what do you leave for integration?See answer

One unit covers pure rules and states with few borders. An integration test checks template, DI, router or HTTP when their composition is part of the behavior. I choose the lowest level that can still detect the actual fault.

How do you eliminate a flaky asynchronous test?See answer

I control clock, scheduler and external responses. I wait for a observable condition instead of using arbitrary delays, close pending requests, and remove shared state between cases.

What does Vitest provide and what does TestBed provide?See answer

Vitest runs suites, assertions, spies and timers. TestBed creates the Angular environment of providers, components and change detection. A pure service may not need TestBed; a component with DI and template usually benefits.

When would you use a component harness?See answer

When multiple tests or consumers need to operate a complex component without relying on its internal DOM. The harness offers stable actions and queries and reduces breakages due to markup changes.

How do you test debounce and retry?See answer

I use fake timers or the virtual scheduler, I advance the clock explicitly and check broadcasts, cancellations and number of attempts. The test does not wait real time nor does it depend on the speed of the machine.

What should a HttpClient test verify?See answer

Method, URL, params, headers and body that are part of the contract; then respond with success or error and check the visible result. verify() ensures that there were no unresolved requests left.

How do you feel about this topic?

23

Web security at Angular

Angular escapes and sanitizes several bindings, but the team still controls authentication, authorization, dependencies, and dangerous data.

Theory

Basics
  • Interpolation and property binding treat values as data. [innerHTML] goes through sanitation; Resource URLs and bypass APIs require strict review.
  • DomSanitizer.bypassSecurityTrust* does not clean content: Creates a value that bypasses sanitization of Angular. Its use concentrates a decision of trust and requires a controlled source, review and audit.
  • Content Security Policy limits the origins and types of resources that the browser can run. Trusted Types forces dangerous DOM sinks to receive values ​​created by registered policies. Together they reduce the impact of an injection reaching the DOM.
Mechanism and application
  • CSRF takes advantage of credentials that the browser automatically attaches, such as cookies. SameSite, an XSRF token, and server validation prove that the request left the expected application. A bearer token prevents that mechanism, but can be stolen by XSS depending on where it is stored.
  • A guard decides navigation on the client and improves the experience, but the user can ignore it or call the API directly. The API must check permissions and ownership for each operation.
Decisions and limits
  • The frontend bundle and its environment variables reach the browser and any user can inspect them. Private keys, service credentials, and secrets belong to the server or a secrets manager.
  • Supported versions of Angular receive fixes; The lockfile sets the installed graph. A supply chain audit reviews vulnerabilities, abandoned packages, installation scripts, and unexpected maintainer changes.

Questions and answers

Does Angular prevent XSS?See answer

Reduces XSS by escaping and sanitizing known contexts. DOM Direct APIs, bypasses, libraries and external HTML reopen the risk.

LocalStorage or cookies for tokens?See answer

It depends on the threat model. HttpOnly cookies reduce reading by XSS and require CSRF controls. LocalStorage simplifies headers but exposes the token to compromised JavaScript.

What does using bypassSecurityTrustHtml entail?See answer

The call does not sanitize the content. Declares that the application trusts that source and bypasses Angular protection for that sink. I restrict it to a revised boundary and prefer to transform data before producing HTML.

Why doesn't a route guard authorize an operation?See answer

The user controls the client and can skip navigation or call the API directly. The guard improves the experience. The server verifies identity, permissions and ownership in each operation.

How would you display HTML provided by users?See answer

I sanitize it with an appropriate policy and library on the server or an audited border, keep CSP and avoid bypassSecurityTrustHtml. If the product supports a subset, I allow only explicit tags and attributes.

Where would you store a session token?See answer

It depends on the threat model. An HttpOnly cookie reduces direct theft by XSS and requires CSRF protection; Memory prevents persistence but is lost on reload. I do not introduce localStorage as the default secure option for long-lived credentials.

How do you feel about this topic?

24

Accessibility, HTML and CSS

Accessibility is part of the UI contract. A Senior integrates it into components and Definition of Done.

Theory

Basics
  • Semantic HTML provides name, role and native behavior. button executes actions, a navigates with href, headings form the index, label names controls and landmarks allow jumping between regions.
  • Keyboard navigation requires a focus order that follows the reading and a visible indicator. A modal moves focus inside, prevents escaping to background content, announces its name, and returns focus to the element that opened it.
Mechanism and application
  • ARIA adds name, role, status, or relationships when native HTML falls short. It does not incorporate a keyboard or behavior by itself; a div role=button still needs focus and activation with Enter and Space.
  • Errors associated with aria-describedby are read along with the control. A live region announces asynchronous changes that do not receive focus, such as the result of a remote operation or validation.
Decisions and limits
  • CSS: cascade, specificity, stacking contexts, box model, Flexbox, Grid, container/media queries and responsive images.
  • Zoom, long text and localization change the dimensions of the content; Contrast and high contrast change your perception; reduced motion limits animations. A flexible component retains readout, focus, and controls without relying on fixed heights.

Theme sources

Questions and answers

Div with click or button?See answer

Button provides keyboard, focus, role and activation without recreating behavior. A div requires implementing and maintaining all of that.

How do you test accessibility?See answer

I combine lint and ax with real keyboard, screen reader in critical flows and review of focus, contrast and accessible names.

When does ARIA make a component worse?See answer

ARIA may contradict native semantics or announce a state that the behavior does not implement. I start with the correct HTML element and add name, status, or relationships only when information is missing.

How do you manage the focus of a modal?See answer

I move focus to a useful point within the dialog, keep the navigation on its content, close with Escape when appropriate, and return focus to the trigger. The dialogue also needs a name and an inert background.

How would you test an accessible modal?See answer

I open it only with the keyboard, I check accessible name, initial focus, Tab cycle, Escape and return of focus. Then I validate the inert background and listen to the flow with VoiceOver or NVDA.

When would you use a live region?See answer

To announce a relevant asynchronous change that does not receive focus, such as a saved result or a remote error. I avoid announcing every press or visual change because it interrupts and overwhelms the screen reader.

How do you feel about this topic?

25

Build, CI/CD, configuration and upgrades

The frontend reaches production through a chain that also requires design and ownership.

Theory

Basics
  • The build configuration contains public values that can be embedded in bundles. The secrets remain outside the frontend. Validating the configuration at startup detects missing URLs or flags and prevents each environment from interpreting different defaults.
  • A CI pipeline runs typecheck, lint, unit tests, build with budgets, and critical walks before publishing. A cache uses the lockfile and configuration as part of its key so as not to reuse incompatible dependencies or results.
Mechanism and application
  • Hashed assets can use long cache because a modification changes their URL. HTML retains a short policy to discover the new release. A rollback requires previous artifacts and temporal compatibility between the new frontend and the previous version of the API.
  • A feature flag separates display from exposition. Owner, metrics and retirement date control its life cycle; a permanent flag maintains two code paths and duplicates test combinations.
Decisions and limits
  • ng update and schematics transform configuration and code for a new version. Updating one major at a time reduces unsupported combinations; deprecations, bundle, and runtime metrics show what work is left after compiling.
  • The source maps relate the minified bundle to the original TypeScript. In production they require restricted access because they reveal structure and code; Associating them with release, commit and event allows you to rebuild the correct stack.

Questions and answers

How do you deploy without breaking users with open tabs?See answer

I maintain temporary API compatibility, handle chunk-load errors, use versioned assets, and avoid deleting previous files before their cache expires.

What do you look at after an upgrade?See answer

Errors, tests, bundles, Web Vitals, warnings, browser support changes and even dependencies. Later I removed obsolete compatibility.

How do you design a secure feature flag?See answer

I define owner, audience, fallback, metrics and retirement date. The backend maintains the authorization rules. Both paths remain tested as long as the flag exists and I remove the code when the rollout ends.

Would you publish source maps in production?See answer

I generate them to relate minified errors to the TypeScript, but I restrict their access to the observability system. I associate each map with release and commit to symbolize the correct stack.

How do you design a frontend rollback?See answer

I keep artifacts immutable per release, maintain temporary API compatibility, and can point hosting back to the previous build. New databases and contracts need a forward-compatible strategy for the old bundle to continue working.

What budget would you put in CI?See answer

Initial bundle limits and critical chunks, typecheck, tests and main path metrics. A budget must fail close to the cause and have owner; an ignored figure in each pipeline does not protect performance.

How do you feel about this topic?

26

Observability, errors and debugging

A Senior designs how to detect and explain failures before the incident occurs.

Theory

Basics
  • The global border captures errors that no feature handled. The log preserves type, cause, and technical context without exposing stack traces, tokens, or personal data in the interface.
  • Release, route, action, correlation ID, anonymized user and breadcrumbs allow a failure to be reconstructed. The same correlation ID propagated by gateway and backend connects the browser error with server logs and traces.
Mechanism and application
  • Error rate indicates frequency, latency per endpoint locates waits, Web Vitals describes rendering and interaction experience, and journey success measures completed tasks. A log without an operational question or an associated action adds volume without diagnosis.
  • Angular DevTools shows tree, DI and profiling. Chrome Performance, Network, Memory and Coverage complete the diagnosis.
Decisions and limits
  • A leak becomes visible when repeating navigation and comparing heap snapshots. Detached DOM nodes, listeners, timers and unlimited caches show which reference keeps alive a view that Angular already destroyed.
  • A feature boundary error contains the fault and provides an output: retry, fallback, partial state, or support contact. A generic toast disappears and does not preserve the operation that the user needs to recover.

Questions and answers

How do you investigate a bug that you don't reproduce?See answer

I increase observable context, compare version, browser and data path, and create a testable hypothesis. I avoid speculative changes without a signal.

What would you report in an HTTP error?See answer

Normalized endpoint, status, duration, correlation ID and operation. I redact or delete body, tokens and personal data.

How do you use a correlation ID from the frontend?See answer

I propagate an allowed identifier in requests and register it along with route, release and action. Backend and gateway keep the same value to link the visible fault with logs and traces without saving personal data.

How do you confirm a browsing memory leak?See answer

I repeat the traversal, force garbage collection in a diagnostic environment and compare heap snapshots. I look for retained components, detached DOM nodes, listeners, timers and caches that preserve references.

How do you distinguish a frontend error from an API error?See answer

I relate the browser event to the backend's request, status, correlation ID and trace. If the API responded well, I check parsing and rendering; If it failed, the same identifier allows the operation to be followed by gateway and service.

What data would you avoid sending to telemetry?See answer

Tokens, passwords, sensitive bodies, unnecessary personal data and complete HTML. I define an allowlist, anonymize identifiers, and apply sampling and retention based on the operational purpose.

How do you feel about this topic?

Block 05

Senior judgment

System design, leadership and interview conversations.

27

System design frontend

In a design interview, start with requirements and go through data, limits, failures, performance and operation.

Theory

Basics
  • Users, critical flows, SEO, offline, real-time, volume, permissions, location and performance objectives form the design constraints. Each constraint modifies the boundaries, data strategy, or rendering mode.
  • A frontend diagram locates features, router, state, API layer, shared components, and domain boundaries. The ownership of each piece of data determines who can write it, who derives it, and how long it should live.
Mechanism and application
  • A cache strategy defines key, TTL and invalidation. Consistency establishes when to accept stale data, how to reconcile optimistic updates, what to do about conflicts, and how to maintain cursors or pages when changing the collection.
  • WebSocket offers persistent bidirectional communication, SSE sends a unidirectional stream over HTTP and polls repeat requests. The solution needs reconnection, ordering, deduplication, and backpressure to not process events faster than the UI can consume them.
Decisions and limits
  • A complete design includes authorization, accessibility, telemetry, test levels, deployment strategy, and migration. These boundaries determine whether the system can be operated and evolved after the first release.
  • The first version covers the scale and known risks with the fewest parts. Observable thresholds, such as latency, volume, or incident frequency, indicate when a strategy is no longer useful and justify the next change.

Questions and answers

Design a dashboard with live dataSee answer

I group widgets by frequency and ownership, use a connection service with multiplexing, normalize events, apply backpressure and render with signals. I pause invisible streams and measure INP.

Design a component librarySee answer

I define design tokens, accessibility and small APIs; I publish harnesses, documentation and semver. I try keyboard, themes, SSR and breaking changes.

How do you choose between WebSocket, SSE and polling?See answer

WebSocket is for bidirectional communication, SSE for a server-to-client stream over HTTP and polling for infrequent changes or simple infrastructure. I compare reconnection, proxies, order, volume and backend support.

What should define a caching strategy?See answer

Defines key, TTL, invalidation, deduplication and stale behavior. It also explains how to reconcile optimistic updates, conflicts, and pagination changes without mixing different user data or filters.

How would you style real-time data without cluttering the UI?See answer

I define useful frequency per widget, group events, deduplicate by version and apply backpressure. I pause consumers out of the viewport and separate the receive rate from the render rate.

What would you include in a system design proposal in addition to the diagram?See answer

Data contracts, ownership, cache strategy, errors, security, accessibility, metrics and rollout. I also leave thresholds that indicate when the first solution needs another architecture.

How do you feel about this topic?

28

Technical leadership and teamwork

The Senior level includes shared decisions, mentoring, incident management and predictable delivery.

Theory

Basics
  • A code review evaluates correctness, security, design and tests. A blocking comment describes a defect that prevents integration; one suggestion proposes an optional improvement. Explaining why allows the author to apply the criteria in future code.
  • A documented technical decision contains context, alternatives and consequences. The review date avoids treating as permanent a choice made under constraints that may change.
Mechanism and application
  • Mentoring makes the mental model visible, increases the difficulty gradually and returns the decision to the learner. Solving each problem for the other person concentrates knowledge and turns the mentor into a bottleneck.
  • During an incident, the team first stabilizes the service, communicates impact, assigns roles, and preserves evidence. The postmortem reconstructs causes and changes code, alerts or processes without looking for culprits.
Decisions and limits
  • Scope negotiation compares risk, dependencies, cost of delay, and incremental delivery. Exposing uncertainty allows you to reserve time, implement the result or reduce the scope before committing to a date.
  • Lead time, defects, maintenance cost, adoption and cognitive load describe technical health from results. Lines of code and number of tickets reward volume even if the system is more complex or less stable.

Questions and answers

How do you resolve a technical disagreement?See answer

I align constraints, compare options with criteria, spike if evidence is missing, and document the decision. Then I support the agreed option.

How did you handle negative feedback?See answer

I described the form modularization case: you listened, reviewed standards, refactored for responsibility, asked for another review, and applied the learning.

What makes a review comment blocking?See answer

Blocking due to correction, security, data loss, broken contract or a debt that prevents the change from operating. I mark preferences as suggestions and explain the risk so the author can apply the criteria.

What do you include in an ADR?See answer

Record context, restrictions, options considered, decision and consequences. I add owner and review date when conditions may change. The document allows the election to be discussed without depending on oral memory.

How do you resolve an architectural disagreement?See answer

We agree on the objective and restrictions, we write alternatives with the same criteria and we execute a spike if the uncertainty requires it. The decision is recorded with consequences and review date.

How do you raise quality without becoming a bottleneck?See answer

I automate repeatable rules, document examples and distribute ownership. In reviews I explain the criteria and allow other people to make decisions with clear limits.

How do you feel about this topic?

29

How to reason and answer as a Senior engineer

This section turns technical knowledge into clear answers. The goal is to demonstrate what happens, what decision you would make, why you would make it, and how you would prove that it worked.

Theory

Basics
  • First answer what the concept is in a sentence. Then explain the mechanism that produces its behavior, choose a specific application and close with the limit of that choice. Example: switchMap replaces the previous internal subscription; I would choose it in a search engine because only the most recent query is of interest, but not to save actions that must all be completed.
  • Separate mechanism from decision. “OnPush reduces checks” describes an effect. “I use OnPush with immutable state because changes arrive through inputs and signals” explains a decision. The second answer shows whether you understand when the tool fits.
  • Name the constraints that change the solution: data volume, update frequency, SEO, latency, accessibility, security, browser support and team capacity. If the question omits them, state your assumptions instead of silently inventing a scenario.
Mechanism and application
  • Compare alternatives with the same criteria. For each option, indicate benefit, cost and failure mode. For example, SSR improves the initial HTML and improves SEO, but adds infrastructure and requires server-friendly code; CSR simplifies the operation, but relies more on JavaScript for the first content.
  • Explain how you would validate the decision. Performance is checked with metrics such as LCP, INP, bundle size or task duration; a migration with tests, telemetry, gradual rollout and rollback; a team improvement with lead time, defects or operational load.
  • A weak answer lists tools: “I would use Signals, OnPush and lazy loading.” A strong answer connects the problem to evidence: “Profiling showed too many checked views; I moved local state to Signals, kept immutable references and measured less scripting time without changing behavior.”
Decisions and limits
  • If you do not remember an exact API, do not invent it. Explain the model you do know, isolate the uncertain detail and say how you would verify it in the documentation or with a minimal test. Correct reasoning is more valuable than an incorrectly memorized signature.
  • For a real experience use Context, Decision, Action and Result. The result must include a verifiable signal: latency, errors, conversion, delivery time, incidents avoided or feedback from the team. If there was no measurement, say what you observed and what you would measure today.

Questions and answers

What differentiates a Senior response?See answer

It is not the number of named APIs. It is being able to explain the mechanism, choose according to restrictions, compare alternatives and propose a way to validate the result. For example, it is not enough to say "I use switchMap": you must explain that it keeps only the most recent internal operation and why that policy matches the problem.

What do you do if you don't know an exact API?See answer

Say which part you know, reason from the Angular model and explain how you would verify the detail. Inventing a signature is more damaging than recognizing an edge.

How do you avoid answering “it depends” without taking a position?See answer

Name two or three decisive conditions, set a reasonable scenario and choose. For example: “If the page needs SEO and quick initial content, I would choose SSR; “If it is an authenticated internal tool, I would start with CSR.” Then explain what information would change the decision.

How do you turn an opinion into a defensible technical decision?See answer

Define the objective, compare alternatives with the same criteria and agree on a sign of success. "I prefer Signals" is an opinion; "I use Signals for synchronous local state because it simplifies derivations and I verify the impact with readability, tests and profiling" is a debatable and measurable decision.

How do you structure a long technical response?See answer

I start with a one-sentence definition, explain the mechanism, and make a decision for a specific scenario. I close with the cost, the alternative and how I would check the result. If the question is broad, I point out that structure so that the interviewer can go deeper where they are interested.

What do you do when the question doesn't include enough context?See answer

I ask for the constraints that really change the answer: volume, change frequency, SEO, latency, consistency, security, and team capacity. If they are not available, I declare an assumption, choose under that scenario and say what information would make me change my option.

How do you feel about this topic?

30

Personal preparation and behavioral responses

Your experience offers solid material. Turn each project into measurable evidence and tailor the introduction to the role.

Theory

Basics
  • A 60 to 90 second pitch connects specialty, years of experience, domains, two achievements and motivation for the role. Going through each job on the CV consumes time without showing the criteria that unites the career.
  • STAR: brief situation and task; action focused on your decisions; result with metrics, learning or risk reduction.
Mechanism and application
  • A behavioral bench covers conflict, error, feedback, leadership, deadlines, uncertainty, incidents, performance and architecture. Each story can answer several questions if it accurately identifies the decision and outcome.
  • The case of dynamic forms demonstrates architecture, Redux or NgRx, scalability and coordination. Number of forms, turnaround time, and before and after defects turn history into measurable evidence.
Decisions and limits
  • The experience since Angular 2 allows us to compare changes in the framework over time. A successful adoption shows benefit and migration; a rejected API shows restrictions and cost that outweighed that benefit.
  • The questions to the interviewer reveal architecture, quality practices, team organization, roadmap, incident management, autonomy and success criteria. The answers allow you to evaluate the real scope of the role.

Questions and answers

tell me about yourselfSee answer

I am a Frontend Developer specialized in Angular, with experience since Angular 2 and distributed teams. I have designed dynamic scale forms and data products. I am looking for a role where I can combine architecture, delivery and mentoring.

Why do you want to change?See answer

Focus on growth, technical scope and type of product. Avoid badmouthing the current team or using a generic response.

How do you prevent a STAR response from becoming too long?See answer

I summarize the situation and task in a few sentences. I dedicate most of it to my decisions, alternatives and coordination. I close with a measurable result and the learning that changed my subsequent work.

How do you tell a mistake without weakening your profile?See answer

I choose a real mistake, explain the decision that produced it, and take responsibility for my part. I describe how I limited the impact, what signal I added, and what code or process change prevented it from happening again.

How do you respond to a technical conflict?See answer

I describe the restriction, each party's position, and how I brought the discussion into evidence. I explain the final decision, my contribution and what changed in the product or the way of working.

How do you talk about a project without historical metrics?See answer

I use verifiable signals such as incidents, delivery time, defects or feedback, and clarify what was not measured. I close with the metric I would implement today instead of making up a number.

How do you feel about this topic?

Block 06

Quick-fire questions

Brief definitions to answer precisely before expanding with mechanism, case and trade-off.

Primitive types?Answer

undefined, null, boolean, number, bigint, string and symbol.

typeof null?Answer

Returns object for historical compatibility; check for null explicitly.

NaN === NaN?Answer

False. Use Number.isNaN or Object.is.

null and undefined?Answer

Null usually expresses intentional absence; undefined expresses lack of value or property.

Truthy and false?Answer

The boolean conversion determines branches; Empty objects and arrays are truthy.

Temporal Dead Zone?Answer

It is the stretch between the entry to the block and the initialization of a let, const or class binding. The binding already belongs to the scope, but reading it throws ReferenceError; for example, console.log(total); let total = 1;.

Hosting?Answer

The environment registers statements before executing; Availability depends on the type of declaration.

this?Answer

Receiver of a call according to call-site, except arrow that captures the external binding.

call, apply, bind?Answer

Call invokes with arguments; apply with array-like; bind creates another function with receiver or set arguments.

Coercion?Answer

Conversion between types. It can be explicit with Number, String, or Boolean, or implicit when an operator or context requires another type.

Closure?Answer

A function preserves the bindings from the lexical environment where it was created, even when it runs after the outer function has finished. It preserves live bindings, not a frozen copy of their values.

Spread and rest?Answer

Same syntax: spread expands; rest gathers remaining values.

Destructuring default?Answer

Applies to undefined, not null.

Shallow copy?Answer

Create a new container and keep the same nested references. With const copy = { ...original }, copy !== original, but copy.user === original.user if user is an object.

structuredClone?Answer

Clone supported structures and cycles; does not clone functions.

Prototype?Answer

Delegate object that JavaScript consults when a property is missing from the receiver.

Own property?Answer

Property defined on the object, testable with Object.hasOwn.

for...in or for...of?Answer

In loops enumerable keys; of loops through values ​​of an iterable.

Mutable array methods?Answer

Push, pop, shift, unshift, splice, sort, reverse, fill and copyWithin.

find or filter?Answer

Find returns the first match; filter creates an array with all of them.

Pure function?Answer

Same result for same inputs and without observable effects.

Currying?Answer

Converts a multi-argument function into a sequence of functions.

Debounce or throttle?Answer

Debounce awaits silence; throttle limits executions per interval.

Promise.all?Answer

Maintain order and reject the first rejection observed.

allSettled?Answer

Waits for all and returns the status of each operation.

AbortController?Answer

Issues a cancellation signal that is consumed by fetch and other APIs.

Does Async block the thread?Answer

No. Await yields the continuation; Synchronous CPU keeps blocking.

Unhandled rejection?Answer

Promise rejected without handler; register it and correct the chain, do not hide it.

DOM?Answer

Tree of nodes and APIs that represent the document.

BOOM?Answer

Outside-of-document browser APIs, such as history, location, and navigator.

Event bubbling?Answer

The event ascends from the target by participating ancestors.

Event delegation?Answer

Listener in an ancestor that decides according to the target; reduce listeners and cover dynamic children.

preventDefault?Answer

Avoid the default action if the event is cancelable.

localStorage?Answer

String synchronous storage by origin and persistent.

IndexedDB?Answer

Asynchronous browser base for structured data and higher volume.

Same-origin?Answer

Matching scheme, host and port.

Preflight?Answer

Request OPTIONS with which the browser queries permission CORS.

ETag?Answer

Representation validator for conditional revalidation.

Service Worker?Answer

Worker with lifecycle that intercepts network and enables offline/push.

Web Worker?Answer

Thread for JavaScript without direct access to DOM.

Semantic label?Answer

Element whose name communicates the role and structure of the navigator and assistive technologies.

head?Answer

Metadata and document resources, not visible main content.

alt?Answer

Textual alternative that depends on the function of the image; decorative use empty alt.

iframe sandbox?Answer

Restricts capabilities of the embedded document and opens with explicit tokens.

GET or POST in form?Answer

GET expresses query and leaves data in URL; POST sends body for an operation.

Submit default?Answer

A button inside a form uses submit if you don't declare type.

defer or async script?Answer

Defer preserves order and expects parsing; async runs when downloading.

Box model?Answer

Content, padding, border and margin.

Specificity?Answer

Weight of a selector within the cascade after origin, importance and layer.

box-sizing:border-box?Answer

The declared width includes padding and border.

Margin or padding?Answer

Margin separates boxes; padding adds space inside the border.

Absolute position?Answer

It leaves the flow and positions itself with respect to its containing block.

Position sticky?Answer

It participates in flow and becomes fixed inside its scroll container when crossing a threshold.

Stacking context?Answer

Scope that limits z-index comparison between descendants.

Pseudo-class or pseudo-element?Answer

Pseudo-class selects state; pseudo-element represents a generated or conceptual part.

BEM?Answer

Block, Element, Modifier convention for class names.

Preprocessor or framework?Answer

Preprocessor extends syntax; framework provides rules, utilities or components.

Media or container query?Answer

Half query viewport/device; container queries container size or style.

Reflow?Answer

Geometry recalculation caused by changes or readings that require layout.

CLS?Answer

Unexpected movement of content; Reserve space for images and asynchronous content.

Component or directive?Answer

The component has a view; The directive adds behavior to a host.

Pure pipe?Answer

Angular can reuse the result as long as the input references do not change.

@for track?Answer

Associate data identity with DOM nodes to minimize creation and preserve state.

computed or effect?Answer

computed derive state; effect synchronizes with an external API.

Signal or BehaviorSubject?Answer

Signal for UI synchronous state; BehaviorSubject when you need semantics and RxJS operators.

switchMap?Answer

Cancels the previous inner when a new issue arrives.

concatMap?Answer

Enqueue inner observables and preserve order.

exhaustMap?Answer

Ignores new shots while the inner is still active.

mergeMap?Answer

Runs inner observables in parallel with configurable concurrency.

forkJoin?Answer

Issue once when everyone completes; fails if any fails and is not useful for infinite streams.

Cold observable?Answer

Each subscription creates its own producer.

shareReplay?Answer

Share and reproduce values; needs refCount, error and override policy.

providedIn: root?Answer

Provider tree-shakeable in the root EnvironmentInjector.

providers local?Answer

New instance in the component's ElementInjector and its visible descendants.

viewProviders?Answer

Hides those providers from the projected content.

InjectionToken?Answer

Typed runtime token for values, functions, or interfaces.

OnPush?Answer

Allows you to skip subtrees until a relevant notification marks the view.

Zoneless?Answer

Angular receives explicit notifications and avoids using ZoneJS to infer changes.

markForCheck?Answer

Mark the view for future verification.

detectChanges?Answer

Run local verification; Frequent use usually indicates faulty flow.

Standalone?Answer

Component that declares dependencies in imports and does not need a declaration in NgModule.

Lazy route?Answer

Load code when navigating to the feature, reducing the initial bundle.

Guard?Answer

Navigation control in client; it does not replace server authorization.

Solve?Answer

Gets data before activating the route.

Reactivate Form?Answer

Explicit model and observable in TypeScript, suitable for complex composition and validation.

CVA?Answer

Contract that connects a custom control with Angular Forms.

Async validator?Answer

Validator that completes with errors or null; Control cancellation and frequency.

Interceptor?Answer

Requests and responses middleware for transversal concerns.

Retry?Answer

Only with policy, limit and idempotence security.

XSS?Answer

Untrusted script execution; Avoid dangerous sinks and maintain sanitation and CSP.

CSRF?Answer

Induced authenticated request from another source; It mainly affects automatic credentials such as cookies.

CSP?Answer

Browser policy that limits script fonts, styles, and other resources.

Trusted Types?Answer

Restrict assignments to dangerous DOM sinks to values created by trusted policies.

SSR?Answer

Render by request on server; helps SEO and initial HTML, adds operational cost.

SSG?Answer

HTML generated in build for stable content.

Hydration?Answer

Angular reuses HTML from server and connect client behavior.

@defer?Answer

Split dependencies and load a view based on trigger or condition.

LCP?Answer

Time to render the largest visible element.

INP?Answer

Observed latency of interactions during the session.

CLS?Answer

Sum of unexpected layout changes.

Tree shaking?Answer

The bundler removes unreachable code when the format and dependencies allow it.

AOT?Answer

Compile templates in build, reduce runtime work and detect errors earlier.

NgRx reducer?Answer

Pure function that calculates new state from state and action.

NgRx effect?Answer

Reacts to events and coordinates I/O or other effects.

Selector?Answer

Derived and memorized query about the store.

Optimistic update?Answer

Update UI before committing and define rollback or reconciliation.

Facade?Answer

Stable API that reduces the surface area of a subsystem; You can hide too much if you don't protect a boundary.

Adapter?Answer

Translate an external contract to the internal model.

Strategy?Answer

Encapsulates interchangeable policies behind a contract.

SRP?Answer

A unit concentrates responsibilities that change for the same reason.

DIP?Answer

High-level code depends on abstractions, not concrete details.

unknown?Answer

Safe type for value not validated; Forces to shake before use.

never?Answer

It represents impossible states and allows exhaustive checks.

Microtask?Answer

Promise queue that is drained before the next macrotask.

Closure?Answer

A function together with its lexical environment: it can keep reading or modifying captured bindings when it runs outside the call that created them.

Immutability?Answer

Create new references instead of mutating shared state; improves predictability and detection.

Object.freeze?Answer

Superficial freezing; it does not protect nested objects without additional work.

Unit test?Answer

Try a unit with controlled boundaries and quick feedback.

Integration test?Answer

Verify collaboration between several units or a real border.

E2E?Answer

Test a user journey through the deployed system or equivalent.

Harness?Answer

Stable API to interact with a component in tests without depending on its internal DOM.

Typical memory leak?Answer

Subscription, listener, timer, observer or cache that preserves a destroyed view.

Correlation ID?Answer

Identifier that connects frontend, gateway, and backend events of an operation.

Feature flag?Answer

Temporary exposure control with owner, metrics and retirement plan.

Micro-frontend?Answer

Frontend unit with independent ownership and deployment, in exchange for integration and duplication.

ADR?Answer

Short record of a decision, alternatives and consequences.

Block 07

Practical cases

  1. 01

    Cancelable search engine

    I built a search engine with debounce, cancellation, loading/error/empty states, query cache and time-controlled tests. Explain why you chose switchMap and what changes if the endpoint does not support cancellation.

  2. 02

    Dynamic forms engine

    Design a schema for types, validation, layout, visibility and permissions. Add a CVA, asynchronous validation, partial persistence and a schema versioning strategy.

  3. 03

    Real-time dashboard

    Design six widgets with different frequencies. I included WebSocket or SSE, reconnect, backpressure, pause outside viewport, cache, permissions and metrics from INP.

  4. 04

    Migration between five major versions

    I proposed stages to update majors, convert features to standalone, introduce control flow, Signals and zoneless. I defined tests, metrics, feature flags and rollback.

  5. 05

    List of 100,000 rows

    Compare server-side paging, virtual scroll, remote filters and caching. I measured memory, scripting, layout and interaction without losing keyboard navigation or screen reader support.

  6. 06

    Authentication refresh race

    Several requests receive 401 at the same time. Design a single refresh, queue, cancellation, secure logout, telemetry and deterministic concurrency tests.

  7. 07

    event loop

    I predicted the order of logs that mix Promises, queueMicrotask, timers, async/await and events. Check the result in the browser and justify each transition between queues.

  8. 08

    Accessible table

    I built a sortable and paginated table with caption, headers, order states, keyboard, focus, loading and empty state. Validate it with a screen reader.

  9. 09

    Responsive layout without CLS

    Implement a card that changes with container queries, respects reduced motion and does not produce jumps. Explain cascade, stacking contexts, overflow and containment.

  10. 10

    Offline cache

    Design HTTP cache, IndexedDB and Service Worker for a reading screen. I defined invalidation, conflicts, quotas, logout and processing of sensitive data.