Preguntas de Angular para entrevistas: signals, componentes e inyección de dependencias
Quick Overview
Ejercicio original Angular22.2.2, Node26.9.0:25checks modelo y35checksDOM JIT/OnPush/zoneless. Mismareferencia qty2total10; reemplazofila/array qty2total20 ysnapshot10. computeddescuentodinámico; raíz/Compartidainstancia1, Localproveedorinstancia2. NoAOT/TypeScript/HTTP/SSR/RxJS/desmontaje/rendimientoprobados.
Para preparar preguntas de Angular para entrevistas, practica cómo cambia un dato, qué cálculo depende de él y qué componente recibe cada instancia del servicio. Un carrito permite comprobar las tres cosas: una cantidad puede subir a dos mientras el total sigue en diez, y dos tarjetas visualmente iguales pueden guardar estados distintos.
Con este ejercicio original puedes ejecutar el código, contrastar las salidas y explicar la causa de cada discrepancia. Si necesitas ampliar después hacia RxJS, formularios o rendimiento, consulta la preparación general de Angular en PracHub. Aquí seguiremos un carrito pequeño hasta su salida visible.

Empieza por una versión y un resultado verificable
El laboratorio usa Angular 22.2.2, componentes standalone, OnPush explícito y provideZonelessChangeDetection(). Se ejecutó con compilación JIT en el navegador; las comprobaciones del modelo usaron Node.js 26.9.0. No presupone que una aplicación anterior tenga esa misma configuración. Antes de responder sobre un proyecto real, pide su versión y cómo arranca.
Hecho oficial: la documentación de Angular sobre ejecución zoneless incluye los eventos manejados por Angular entre las notificaciones que programan trabajo de sincronización. Eso ayuda a interpretar este caso, pero no demuestra que cualquier cambio externo actualice cualquier vista.
Resultado observado: se verificaron 25 comparaciones del modelo y 35 comprobaciones del DOM mediante botones reales. El paquete conserva el código, las 25 comparaciones en model-results.json y las 35 observaciones comprobadas en native-browser-results.json. No se probaron compilación AOT, tipos de TypeScript, HTTP, SSR, operadores de RxJS ni rendimiento bajo carga.
Relatos de candidatos: no usamos testimonios para afirmar qué preguntará una empresa. Las preguntas enlazadas al final son material publicado de práctica. Recomendación de preparación: responde primero con una predicción concreta y después contrástala con la ejecución; esa secuencia es nuestra propuesta, no una regla de contratación.
Distingue un signal de una copia de su valor
Un signal contiene un valor y permite leerlo llamándolo como función. Un computed expresa un cálculo dependiente de lecturas reactivas. En nuestro carrito, items contiene una fila: producto A, cantidad uno y precio diez. total multiplica cantidad por precio y suma las filas.
El componente muestra store.total() y también guarda snapshot = this.store.total() al construirse. Ambas expresiones producen diez al principio; después, la plantilla vuelve a leer total(), mientras snapshot conserva el número inicial. snapshot es un número ordinario capturado en ese momento; no se convierte en cálculo reactivo por haber salido de un signal.
Resultado del ejercicio: después de reemplazar la fila por otra con cantidad dos, el total mostrado pasa a veinte y la copia inicial continúa en diez. No hace falta atribuirlo a un error de renderizado: el componente está mostrando correctamente dos valores con reglas distintas.
En una respuesta oral, identifica cuál necesita el producto. Una copia inicial sirve, por ejemplo, para comparar el valor de apertura con el actual. Si la etiqueta promete «total actual», guardar solamente ese número inicial incumple la intención. El nombre del campo y la expectativa del usuario deben coincidir antes de modificar el código.
Esta distinción también orienta la prueba. Comprobar únicamente que el componente existe no descubre el problema. Hay que cambiar la cantidad y verificar por separado el total actual y la copia inicial, con valores esperados distintos.
Por qué la cantidad llega a dos y el total queda en diez
La variante defectuosa modifica la fila existente y devuelve el mismo array:
mutateSameReference() {
this.items.update(rows => {
rows[0].qty++;
return rows;
});
}
Hecho oficial: Angular usa Object.is como comparación predeterminada de signals; su guía de Signals también aclara que exponerlos como readonly no impide mutaciones profundas. En este laboratorio no configuramos una igualdad personalizada.
Al pulsar «Mutar misma referencia», la cantidad almacenada realmente pasa a dos. El evento provoca trabajo sobre la vista y la lectura directa de items()[0].qty muestra dos. Sin embargo, total ya había calculado diez y conserva su resultado: la escritura no proporcionó un array diferente que invalidase esa dependencia.
La conclusión es «el dato anidado cambió, pero el cálculo conservó su caché». No basta decir «Angular no se enteró de nada», porque una parte de la pantalla sí cambió. Si alguien ve dos unidades y un total de diez, necesita una explicación para esa contradicción visible. Comprueba ambas lecturas antes de cambiar la estrategia del componente.
La corrección del ejemplo crea tanto otro array como otra fila. En las comprobaciones, la fila anterior sigue con cantidad uno y las identidades del array y de la fila nueva son distintas. El método publica ese nuevo estado mediante update:
replaceChangedRow() {
this.items.update(rows =>
rows.map(row => ({...row, qty: row.qty + 1}))
);
}
Compara ambas rutas desde el mismo inicio: cantidad uno, total diez. Restablece el carrito entre ellas; si primero mutas a dos y después incrementas otra vez, obtendrás tres y estarás comparando entradas distintas. Nuestro caso tiene una sola fila: una tienda con varios productos necesitaría seleccionar el SKU correspondiente y añadir esa prueba.
Las dependencias de computed cambian con la rama ejecutada
El importe final añade un descuento opcional. Cuando está desactivado, due lee el indicador y el total. Cuando está activado, lee además el descuento. El código completo está en store.mjs; un contador de diagnóstico registra cuántas veces se ejecuta la derivación.
Resultado observado: desde total diez y descuento desactivado, aumentar el descuento de dos a tres mantiene el importe en diez y no incrementa el contador de due. Activarlo produce siete. Aumentarlo después a cuatro produce seis. Desactivarlo devuelve diez; cambiar entonces el descuento a cinco vuelve a dejar el contador sin cambios.
Estas salidas muestran qué lecturas estaban activas. Si ignoras la rama ejecutada, puedes intentar corregir un importe de diez que ya era el resultado esperado. La dependencia del descuento aparece al recorrer la rama que lo consulta y deja de ser necesaria al salir de ella. El contador es instrumentación del laboratorio; no es una métrica de rendimiento de una aplicación comercial.
Si te piden explicar una actualización «perdida», dibuja primero la última ruta ejecutada. ¿Se leyó ese signal en esa evaluación? ¿Se volvió a leer el cálculo después de invalidarlo? ¿Había realmente un valor diferente? Son preguntas comprobables antes de añadir una sincronización imperativa entre campos.
Para este importe, mantener otro campo escribible con una copia del resultado añadiría una segunda cosa que actualizar correctamente. La relación ya cabe en una derivación. Si el requisito cambiara a guardar el precio aceptado de una compra, necesitaríamos modelar ese hecho persistido; no sería automáticamente el mismo problema que mostrar el carrito actual.
Dos componentes iguales pueden inyectar carritos diferentes
El servicio se registra con providedIn: 'root'. El componente raíz y la tarjeta «Compartida» llaman a inject(CartStore) sin añadir un proveedor local. La tarjeta «Local», en cambio, declara providers: [CartStore] en su configuración.
Hecho oficial: la inyección jerárquica de Angular resuelve un proveedor cercano antes de continuar por los ancestros. Por tanto, registrar una clase en raíz no obliga a todas las peticiones a usar siempre esa instancia si existe otro proveedor aplicable.
Resultado observado: raíz y Compartida muestran identificador uno; Local muestra dos. Los identificadores son contadores del ejemplo para reconocer objetos, no credenciales ni identificadores de usuario. Tras incrementar Local y restablecer raíz, las salidas son:
| Vista | Instancia observada | Total después de restablecer raíz | Explicación en este árbol |
|---|---|---|---|
| Carrito raíz | 1 | 10 | Restablecemos su estado |
| Compartida | 1 | 10 | Lee el mismo carrito que raíz |
| Local | 2 | 20 | Su proveedor mantiene otro carrito |

El contraste localiza el problema: la plantilla puede estar funcionando y el servicio puede actualizarse correctamente, pero la persona observa otra instancia. Revisa dónde se declara el proveedor antes de añadir suscripciones o forzar comprobaciones de vistas.
La elección de ámbito depende del requisito. Si las dos tarjetas representan el mismo carrito, quitar el proveedor local podría recuperar la propiedad compartida esperada. Si son borradores independientes, aislarlas puede ser precisamente lo correcto. En ambos casos, describe quién puede modificar el estado y qué debe ocurrir cuando se cierra esa vista.
El experimento comprueba identidad y aislamiento mientras los componentes están montados. No contiene una prueba de desmontaje y destrucción del servicio. Presenta esa comprobación como trabajo siguiente si la conversación trata de limpieza de recursos; no la des por realizada a partir del número de instancia.
Comprueba el modelo y después el comportamiento visible
Puedes descargar el laboratorio y sus resultados y abrir la miniaplicación siguiendo el README. Incluye versiones fijadas y un bundle ya generado. El servidor estático local solo sirve archivos: no existe un backend que confirme pedidos o sincronice carritos entre navegadores.
Las 25 comprobaciones con Angular real bajo Node verifican referencias, valores calculados y dependencias condicionales. También muestran que la vista readonly permite mutar la cantidad anidada a nueve en JavaScript; no prueban restricciones del compilador TypeScript. Las 35 comprobaciones del navegador añaden lo que ese nivel no establece: botones, salida del componente, identidades inyectadas y aislamiento visible entre tarjetas.
Hecho oficial: la documentación de pruebas de componentes distingue la clase del componente de su plantilla y comportamiento conjunto. Nuestra ejecución usa la aplicación real y observaciones del DOM; no presenta sus resultados como una suite ejecutada con TestBed.
Para repetir el fallo, carga la página, anota cantidad uno y total diez, pulsa la mutación y verifica cantidad dos con total diez. Restablece raíz, pulsa reemplazo y verifica cantidad dos con total veinte y copia inicial diez. Después incrementa Local, restablece raíz y compara las dos instancias.
Guarda un resultado esperado por observación. «La pantalla se actualiza» admite demasiadas interpretaciones; «la tarjeta local conserva veinte mientras Compartida vuelve a diez» identifica el contrato comprobado. Tampoco conviertas el tamaño del bundle JIT de desarrollo en una conclusión sobre el peso de una aplicación optimizada.
Convierte el diagnóstico en una respuesta de entrevista
Una respuesta breve puede seguir este recorrido: «Veo cantidad dos y total diez. Primero confirmo que son lecturas del mismo servicio. Después reviso si el array conservó su referencia. El total es un cálculo almacenado en caché; voy a reemplazar la fila y verificar el resultado desde el estado inicial».
Tu compañero puede replicar: «¿Y si otra tarjeta sigue mostrando diez?». Responde con una comprobación adicional: comparar las identidades y buscar providers en el componente. No prometas que el primer cambio arregla un ámbito de inyección diferente. Cada hipótesis necesita su propia evidencia.
Otra pregunta útil es «¿Por qué no cambió el importe al aumentar el descuento?». Antes de considerarlo un fallo, observa si el descuento estaba activado. La salida de diez es correcta en la rama desactivada; lo importante es justificar también cuándo el cálculo incorpora esa dependencia.
Si desconoces una API, delimita lo que sabes y abre la referencia pertinente. Puedes seguir razonando sobre entradas, referencias y propiedad del estado sin inventar el comportamiento de una versión que no has usado. Esa claridad permite que la conversación avance con una prueba pequeña.
Practica con cinco preguntas de PracHub
Los dos primeros títulos tratan Angular directamente. Los otros permiten practicar decisiones de estado y componentes con este framework; su título general no demuestra que se plantearan originalmente como exámenes de Angular. No son una predicción de tu próxima entrevista.
| Pregunta completa | Qué practicar con este carrito |
|---|---|
| Describe Angular features | Relaciona signals, plantilla y DI con una salida concreta |
| Debug an Angular UI from User Reports | Reproduce cantidad dos y total diez antes de proponer cambios |
| Debug a Frontend Component That Shows Wrong API Results | Separa el dato recibido de su propietario y del valor mostrado; añade HTTP como extensión |
| Compare front-end state management approaches | Compara estado compartido, aislamiento y derivaciones verificables |
| Design a Notification UI with History and Live Updates | Explica qué estado necesita historial; el carrito actual no implementa eventos en directo |
Empieza por Debug an Angular UI from User Reports: escribe el estado inicial, predice las tres salidas y explica qué observación descartaría tu hipótesis. Después cambia solo una referencia o un proveedor y repite la prueba. Esa evidencia te da una respuesta técnica que puedes defender ante una pregunta adicional.
Comments (0)