Tag: Angular 22

  • Ciclo de releases de Angular: una major cada 12 meses

    Ciclo de releases de Angular: una major cada 12 meses

    El 24 de julio de 2026 se mergeó un PR en el repositorio de Angular. Número 69817. Título: docs: add v23 release and change to yearly release cycle.

    Un PR de documentación. Sin keynote, sin post oficial, sin hilo en X. Una línea de docs sobre el ciclo de releases de Angular, mergeada en main y backporteada a las ramas 22.0.x y 22.1.x.

    Dentro va un cambio que decide cómo planificas los próximos tres años de tu proyecto: se pasa de una major cada seis meses a una major cada doce.

    Se mergeó el 24 de julio de 2026 y apenas ha circulado. La mayoría de los equipos se va a enterar el día que abra el calendario del año que viene para reservar su ventana de migración y no encuentre nada donde esperaba encontrar una major.

    En corto: desde Angular v22, Angular publica una versión major cada 12 meses en lugar de cada 6. La siguiente major, Angular v23, está fechada para junio de 2027. Entre medias llegan de 4 a 6 minors con features nuevas, y los patches siguen saliendo casi cada semana.

    Qué cambia exactamente en el ciclo de releases de Angular

    Angular publica una major cada 12 meses desde la v22. Antes eran 6. Los datos son cortos:

    Tipo de release Hasta Angular v21 Desde Angular v22
    Versión major cada 6 meses cada 12 meses
    Minors por cada major 1-3 4-6
    Patches y pre-releases (next / rc) casi cada semana casi cada semana
    Soporte activo por major ~6 meses 12 meses
    Soporte total (activo + LTS) ~18 meses 24 meses

    Fuente: Versioning and releases, documentación oficial de Angular.

    La justificación oficial, traducida:

    "La comunidad lleva mucho tiempo pidiendo majors menos frecuentes por el impacto que tienen los breaking changes y las actualizaciones, tanto en sus proyectos como en clientes enterprise. Además, un ciclo de release más largo proporciona mayor estabilidad de API para los developers que usan flujos de trabajo agénticos, sin dejar de entregar una cadencia razonable de mejoras y migraciones de API."

    PR #69817, repositorio oficial de Angular.

    Dos motivos. El segundo es el interesante, y vuelvo a él más abajo.

    ¿Cuándo sale Angular v23? El calendario del nuevo ciclo

    Angular v23.0 está fechada para junio de 2027, según el calendario oficial de releases. Hasta entonces la v22 recibe entre 4 y 6 minors —de la v22.1 a la v22.5— programadas hasta principios de 2027.

    Versión Fecha
    Angular v22.0 junio de 2026 (publicada)
    Minors v22.1 – v22.5 hasta principios de 2027
    Angular v23.0 ~ junio de 2027

    Y el ciclo anual también alarga el soporte. Cada major pasa a tener 24 meses de vida: 12 de soporte activo, con actualizaciones y parches regulares, y 12 más de LTS, solo con fixes críticos y de seguridad. En la práctica, Angular v22 tiene soporte activo hasta junio de 2027 y LTS hasta junio de 2028; la v21, con el ciclo viejo, tuvo activo poco más de seis meses.

    Tienes más margen. Pero el salto que te espera al final del margen es el doble de grande.

    Lo que no cambia: las features siguen saliendo en las minors

    Angular no ha frenado el desarrollo: las features siguen saliendo en las minors. Este es el malentendido que va a circular la semana que viene, así que lo corto ya.

    Lo único que queda restringido a las majors son los breaking changes. Las features siguen entrando por las minors, exactamente igual que hasta ahora.

    Y como las minors pasan de 1-3 por major a 4-6, el goteo de novedades no se corta. Si acaso, se estira.

    Lo que baja no es la velocidad de features. Es la frecuencia con la que Angular te obliga a tocar tu código.

    Si has seguido las novedades de Angular v22, ya sabes que el grueso de lo interesante llega goteando y no de golpe en el día de la major.

    Por qué el ciclo anual no te quita el trabajo de migración: cambia cuándo llega

    Un ciclo anual reduce el número de migraciones. Que reduzca el trabajo está por demostrar. Lo que hace seguro es agruparlo. Y es lo contrario de lo que vas a leer en los resúmenes de la noticia.

    Antes tenías un salto pequeño cada seis meses. Ahora tienes uno grande cada doce.

    Lo que baja seguro es el número de veces que paras: de seis eventos de migración en tres años a tres. Lo que no está anunciado en ninguna parte es que baje el volumen de cambios de API que tienes que absorber. Angular no ha dicho que vaya a romper menos cosas. Ha dicho que las va a agrupar.

    Puede que agrupar reduzca algo el total —dos cambios sobre la misma API en doce meses te llegan ya resueltos en uno—, pero eso está por ver. Lo que está decidido hoy es el reparto.

    Y el reparto no afecta igual a todos.

    Si vas al día, ganas. La mitad de migraciones que rompen algo, la mitad de ceremonias de actualización, la mitad de veces que paras un sprint para ejecutar ng update y arreglar lo que se ha roto. Para un equipo con disciplina, esto es dinero directo.

    Si arrastras retraso, pierdes. Un salto de doce meses no son dos saltos de seis pegados: es un salto en el que no puedes bisecar. Cuando algo se rompe tienes el doble de superficie donde buscar la causa, y las migraciones automáticas dejan de llevarte de la mano versión a versión. Si vienes de v17 o v18, ya hice el mapa de qué migrar primero, y ese orden importa más ahora que antes. Ya conté también el coste real de migrar a Angular 22, y ese coste no se reparte a la mitad por espaciarlo.

    Pero el problema de verdad no es el tamaño del salto.

    Es que una ventana más larga hace mucho más fácil quedarse atrás sin notarlo.

    Cuando la siguiente major está a seis meses, el retraso duele pronto. Te saltas una y en medio año ya tienes a alguien preguntando por qué seguís dos versiones por detrás.

    Cuando está a un año, la deuda no avisa. Las minors siguen ahí, pero una minor no te obliga a nada: la ignoras y no pasa nada. Lo que desaparece no son los avisos. Es el único aviso que no podías ignorar. Y la deuda técnica que no genera incomodidad es justo la que nadie prioriza.

    El ciclo anual es más cómodo. Y la comodidad, en gestión de dependencias, casi siempre se paga después.

    Por qué Angular justifica el ciclo anual con los agentes de IA

    Angular justifica su nueva cadencia, en parte, por cómo trabajan los agentes de código. Vuelve a la cita oficial y lee la segunda mitad: "proporciona mayor estabilidad de API para los developers que usan flujos de trabajo agénticos".

    Piensa en lo que significa. Un modelo que te ayuda a escribir Angular ha aprendido de código de muchas versiones a la vez. Cuando las APIs cambian cada seis meses, la probabilidad de que te proponga algo que ya no existe —un decorador retirado, una firma vieja, un patrón de la versión anterior— sube. Y ese código llega a tu PR con aspecto perfectamente razonable.

    Cada breaking change es ruido en lo que el modelo cree saber.

    Con dos matices que conviene poner encima de la mesa, porque son los que hacen el argumento correcto en vez de solo bonito.

    El primero: lo que pesa no es la frecuencia en abstracto, es cuántas majors han pasado desde el corte de entrenamiento del modelo que tienes abierto. Con majors anuales ese número se parte por la mitad, y un modelo de la misma edad sigue estando en lo cierto durante el doble de tiempo.

    El segundo: las versiones viejas no desaparecen. Angular 14 sigue en el corpus y seguirá. Bajar la cadencia no borra lo aprendido, solo frena lo que se acumula a partir de ahora. El efecto es real, pero se mide en años, no en el próximo release. Y un agente que trabaja con la documentación en contexto depende mucho menos de lo que recuerde: la cadencia importa sobre todo cuando el modelo tira de memoria.

    Que un framework grande diga esto en voz alta, aunque sea en un PR de documentación, es nuevo. Hasta ahora la cadencia se discutía pensando solo en humanos: cuánto aguanta un equipo, cuánto tarda una empresa en aprobar una subida de versión.

    Ahora entra un tercer actor en la conversación, y es el que escribe una parte creciente del código.

    No es una nota al pie. Es una señal de cómo se van a diseñar las herramientas los próximos años: asumiendo que quien las consume no siempre es una persona. Es una de las conversaciones que más tenemos en Dominicode Labs, porque cambia decisiones de arquitectura que hasta ayer parecían cerradas.

    Cómo planificar la migración de Angular con el nuevo ciclo de releases

    Tres cambios concretos en tu forma de trabajar.

    1. La actualización deja de ser un evento reactivo y pasa a ser una fecha

    Antes funcionaba el "ya actualizaremos cuando salga la siguiente". Con una major cada seis meses, ese reflejo te mantenía razonablemente cerca del head. Con una cada doce, ese mismo reflejo te regala un año entero para no hacer nada.

    Pon la ventana ahora. Angular v23 está fechada para junio de 2027: reserva las semanas en el roadmap antes de que el trimestre se llene de otra cosa.

    Y si no eres tú quien decide el roadmap, la versión pequeña es abrir el issue con las dos fechas escritas y dejarlo ahí. Cuando llegue la discusión —y va a llegar—, ya existe un sitio donde el tema está planteado y con tu nombre encima.

    2. Trata las minors como el ritmo real de adopción

    Con 4-6 minors por año, la minor es la unidad de trabajo, no la major. Un equipo que va absorbiendo minors llega a la major con medio trabajo hecho: los deprecation warnings ya los ha visto, las migraciones automáticas ya las ha corrido, el código nuevo ya usa las APIs nuevas.

    Un equipo que solo se mueve en majors llega a junio de 2027 con doce meses de sorpresas juntas.

    3. Asume que saltarte una major te deja el doble de lejos que antes

    Saltarte una major te ponía a doce meses de distancia del head. Ahora te pone a veinticuatro. Ese es el número que tienes que enseñar a quien decida si hay tiempo para actualizar o no.

    Un gesto concreto para empezar: ejecuta ng update sin argumentos. Te lista qué paquetes tienen actualización pendiente y a qué versión, sin tocar nada. Es el inventario en treinta segundos.

    4. Monta la red antes del salto, no durante

    Lo que convierte un salto grande en algo manejable es tener algo que te diga en cinco minutos qué se ha roto. Si tu proyecto sigue en Karma, Vitest ya es el default en Angular 22, y ese cambio se hace mejor ahora, con tiempo, que en mitad de la migración a la v23. Cómo montar esa suite —los patrones son los mismos con Jest o con Vitest— lo cubro paso a paso en el curso de Testing en Angular.

    Lo mismo aplica al resto del stack: migrar a TypeScript 6.0 con strict antes del salto convierte errores de runtime en errores de compilación, que es donde los quieres. Y si estás mirando más adelante, TypeScript 7.0 y su compilador en Go es la otra pieza del calendario que conviene tener en el radar.

    Lo que yo haría esta semana

    Abre el roadmap y escribe dos fechas: la de tu próxima adopción de minor y la ventana de la v23 en junio de 2027.

    Diez minutos. Es la diferencia entre llegar a la v23 con una actualización planificada o con una emergencia.

    Si estás poniendo al día un proyecto y quieres el mapa completo de lo que ha cambiado —signals, zoneless, el modelo mental nuevo—, lo tienes ordenado en el curso de Angular Moderno.

    El ciclo anual te ha dado más margen. Y el margen sin fecha no es margen: es aplazamiento.

    Preguntas frecuentes sobre el ciclo de releases de Angular

    ¿Cada cuánto sale ahora una versión major de Angular?

    Angular publica una versión major cada 12 meses a partir de la v22. Hasta ese cambio, el ciclo era de una major cada 6 meses. Entre major y major salen ahora entre 4 y 6 minors, frente a las 1-3 del ciclo anterior.

    ¿Hasta cuándo tiene soporte Angular 22?

    Angular v22 tiene soporte activo hasta junio de 2027 y soporte LTS hasta junio de 2028. Con el ciclo anual, cada versión major pasa a tener 24 meses de soporte en total: 12 meses de fase activa, con actualizaciones y parches regulares, y 12 meses de LTS, en los que solo se publican fixes críticos y de seguridad.

    ¿Cuándo sale Angular v23?

    Angular v23.0 está fechada para junio de 2027 aproximadamente, según el calendario oficial de releases. Hasta entonces las novedades llegan por las minors de la v22: de la v22.1 a la v22.5, programadas hasta principios de 2027.

    ¿Significa esto que Angular se ha ralentizado?

    No. Las features siguen saliendo en las minors, y ahora hay más minors por ciclo: entre 4 y 6 en lugar de 1-3. Lo único que queda restringido a las versiones major son los breaking changes. Los patches y las pre-releases next y rc siguen publicándose casi cada semana, igual que antes.

    ¿Qué pasa si voy retrasado varias versiones de Angular?

    Un proyecto retrasado sale perdiendo con el ciclo anual, porque cada salto de major concentra doce meses de breaking changes en lugar de seis. Además, una ventana más larga hace más fácil acumular retraso sin darse cuenta: no hay una major cercana que recuerde lo lejos que estás. Si arrastras versiones, ponte al día antes de junio de 2027 y hazlo en saltos pequeños, versión a versión, en vez de esperar a hacerlo todo junto.

    ¿Conviene esperar a Angular v23 para migrar?

    No conviene esperar. Llegar a junio de 2027 con el trabajo de la v22 sin hacer significa sumar dos saltos en una sola operación, con el doble de superficie que puede romperse a la vez. La estrategia que funciona es adoptar las minors de la v22 según salen y presentarse en la major con las migraciones automáticas ya ejecutadas y los deprecation warnings ya resueltos.


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Novedades de ECMAScript 2026 (ES17) en JavaScript

    Novedades de ECMAScript 2026 (ES17) en JavaScript

    Si llevas unos años programando en JavaScript, seguro que has tenido que lidiar con el clásico error de precisión aritmética: intentar sumar 0.1 y 0.2 en la consola de tu navegador y ver cómo devuelve 0.30000000000000004.

    Durante décadas, la respuesta de la comunidad ha sido la misma: "Es cosa del estándar IEEE 754 de coma flotante, acéptalo, redondea a mano o usa una librería externa".

    Por fin, Ecma International ha decidido poner fin a este y otros parches históricos con la aprobación oficial de ECMAScript 2026 (ES17).

    Hoy te quiero enseñar las características más importantes de este nuevo estándar que cambiarán tu forma de escribir JavaScript en tu día a día, y cuáles son las esperadas funciones que se han quedado a las puertas.


    Las características estrella de ES2026

    La versión 17 de la especificación oficial se centra en cerrar brechas históricas de la ergonomía del lenguaje, manipulación de datos binarios y control de errores:

    1. Math.sumPrecise (Suma exacta de flotantes)

    Se acabó el usar librerías externas o el típico truco de multiplicar por 100 y luego dividir solo para sumar decimales. El nuevo método Math.sumPrecise recibe un iterable de números y realiza una suma compensando matemáticamente las pérdidas de precisión de la coma flotante.

    const valores = [0.1, 0.2];
    // JavaScript tradicional: valores[0] + valores[1] => 0.30000000000000004
    const totalExacto = Math.sumPrecise(valores); // => 0.3
    

    2. Error.isError (Validación robusta de excepciones)

    Comprobar si un objeto capturado en un bloque catch es un error real mediante instanceof Error es frágil. Si el error proviene de otro contexto de ejecución (como un iframe en el navegador o un Web Worker en Node/Deno), la validación suele fallar. Error.isError soluciona esto aportando un chequeo universal y fiable a nivel interno del motor JS.

    3. Codificación nativa Hex y Base64 en Uint8Array

    Hasta ahora, convertir datos binarios a texto hexadecimal o Base64 requería funciones auxiliares complejas (Buffer.toString en Node o btoa/atob en navegador). ES2026 introduce métodos nativos directamente en el prototipo de Uint8Array para realizar conversiones de forma directa y de altísimo rendimiento.

    4. Valores por defecto en Mapas (Map.prototype)

    Se añaden nuevos métodos a Map y WeakMap para poder insertar un valor por defecto si una clave no existe en el mapa, simplificando la escritura de cachés o contadores.

    const visitas = new Map();
    // Inserta 1 si la clave no existe, o incrementa el valor actual
    visitas.getOrInsert("usuario_123", 0);
    

    5. Array.fromAsync e Iterator.concat

    Trabajar con generadores y flujos asíncronos ahora es mucho más ergonómico. Array.fromAsync permite construir un array a partir de iterables asíncronos de forma limpia, mientras que Iterator.concat facilita la unión de múltiples secuencias sin necesidad de cargarlas completas en memoria.


    Lo que se queda fuera (Las ausencias destacadas)

    A pesar de las altas expectativas que había durante su fase de desarrollo, algunas de las propuestas más esperadas no lograron entrar en la especificación final aprobada este año:

    • Temporal API (El nuevo Date): Aunque la comunidad lleva años demandando un reemplazo moderno, consistente y no mutable para el desastroso objeto Date tradicional, la API de Temporal sigue en revisión técnica activa y no forma parte del estándar oficial de 2026.
    • Explicit Resource Management (using): La esperada sintaxis de liberación automática de recursos (similar a la que encontramos en lenguajes como C# o TypeScript con la palabra clave using) tampoco logró cerrarse a tiempo para esta edición.

    Escribe código preparado para el futuro

    La evolución de JavaScript demuestra una clara tendencia a madurar el lenguaje, absorbiendo utilidades que antes requerían librerías de terceros (como Lodash o parches de buffer binario). Como vimos en nuestro post sobre oMLX y TypeScript en Mac, escribir código nativo limpio sobre los frameworks optimizados es la clave de la eficiencia en el desarrollo moderno.

    Adoptar las mejores prácticas de TypeScript avanzado y escribir código nativo limpio es exactamente el enfoque de calidad de software que defendemos en el curso de Construye con IA para estructurar aplicaciones robustas de producción.


    Conclusión: Simplifica tu código

    No sigas arrastrando dependencias externas para resolver tareas de precisión matemática básica o conversiones binarias. Revisa la documentación de ECMAScript 2026 y aprovecha las nuevas capacidades integradas del motor de JavaScript para limpiar tu código y mejorar la velocidad de tus ejecuciones.

    Si quieres debatir sobre el futuro de las APIs de JavaScript, patrones de TypeScript avanzado y compartir configuraciones de compilación con otros desarrolladores senior, te espero en Dominicode Labs.


    Preguntas Frecuentes (FAQ)

    ¿Cuándo podré usar las funciones de ES2026 en navegadores?

    La especificación ya ha sido aprobada de forma oficial. Los motores principales (V8 de Chrome/Node, JavaScriptCore de Safari y SpiderMonkey de Firefox) ya han implementado la mayoría de estas funciones de forma de forma experimental. Puedes utilizarlas hoy mismo actualizando tus entornos de desarrollo de Node.js o mediante polyfills si necesitas soporte para navegadores antiguos.

    ¿Cómo ayuda Math.sumPrecise con el rendimiento de arrays grandes?

    Math.sumPrecise está optimizado a nivel de compilación nativa en C++ en los motores de los navegadores. Al delegar la suma compensada de precisión directamente al motor en lugar de ejecutar un bucle con lógica de redondeo en JavaScript, la velocidad de procesamiento de grandes volúmenes de datos numéricos mejora sustancialmente.

    ¿Por qué instanceof Error falla en iframes y Web Workers?

    Porque cada iframe o Web Worker crea un contexto de ejecución global diferente (un Realm distinto) con su propio constructor Error. Por lo tanto, un error lanzado dentro de un iframe no se reconoce como instancia del objeto Error de la ventana principal de navegación, problema que resuelve el nuevo chequeo estático Error.isError.

    ¿Qué sucederá con la API de Temporal?

    La API de Temporal sigue estando en fase activa de desarrollo de Stage 3/4. Es una especificación sumamente compleja debido a la gestión de zonas horarias y calendarios. Es muy probable que se apruebe formalmente para la próxima iteración del estándar (ECMAScript 2027).


    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.

  • Resource API en Angular 22: el fin del subscribe() manual

    Resource API en Angular 22: el fin del subscribe() manual

    Revisé hace poco un componente de Angular que cargaba una lista de productos. Contaba los observables con los dedos: un BehaviorSubject para la categoría seleccionada, un switchMap hacia HttpClient, un catchError para los fallos, un takeUntilDestroyed para no dejar suscripciones vivas, y al final, un async pipe en el template.

    Todo correcto. Todo necesario. Y todo código que explica exactamente lo mismo que cualquier otro componente de carga de datos en la aplicación. La Resource API de Angular 22 resuelve exactamente este problema.

    Ese patrón tiene quince años. Angular 22 tiene la respuesta definitiva.

    Qué es la Resource API y por qué existe

    La Resource API es el mecanismo nativo de Angular para gestionar operaciones asíncronas dentro del sistema de Signals. No es una librería de terceros, no es un wrapper sobre RxJS: es la pieza que faltaba para que el modelo reactivo de Angular estuviera completo.

    La idea central es sencilla: tienes un signal que representa un parámetro (un ID, un filtro, una página), y quieres que Angular haga automáticamente el fetch cuando ese parámetro cambia. Sin subscribe, sin pipe, sin gestión manual del ciclo de vida.

    En Angular 22 el ecosistema completo se compone de tres APIs:

    • resource() — fetch genérico con Promise. Estable en v22.
    • rxResource() — puente para servicios basados en Observable. Estable en v22.
    • httpResource() — wrapper declarativo sobre HttpClient. Experimental en v22.

    El matiz de los estados de estabilidad importa. resource() y rxResource() ya son API pública con garantías de compatibilidad. httpResource() sigue marcado como experimental — la API puede cambiar. Para producción crítica, ten eso en cuenta.

    resource(): el punto de entrada

    Usa resource() cuando el origen de datos es una Promise o una función fetch directa. El parámetro reactivo se define en params, y la función que carga los datos en loader.

    import { ChangeDetectionStrategy, Component, signal, resource } from '@angular/core';
    

    interface Producto { id: number; nombre: string; }

    @Component({ selector: 'app-catalogo', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @switch (productos.status()) { @case ('loading') { <p>Cargando...</p> } @case ('reloading') { <p>Actualizando...</p> } @case ('error') { <p>Error: {{ productos.error() }}</p> } @default { @if (productos.hasValue()) { <ul> @for (p of productos.value(); track p.id) { <li>{{ p.nombre }}</li> } </ul> } } } <button (click)="categoria.set(categoria() + 1)">Siguiente</button> <button (click)="productos.reload()">Recargar</button> `, }) export class CatalogoComponent { categoria = signal(1);

    productos = resource<Producto[], { cat: number }>({ params: () => ({ cat: this.categoria() }), loader: ({ params, abortSignal }) => fetch(/api/products?category=${params.cat}, { signal: abortSignal }) .then(r => r.json()), }); }

    Dos errores que verás en código antiguo o en tutoriales desactualizados:

    • El campo se llama params, no request. Eso era la API experimental anterior.
    • Los estados son strings literales: 'loading', 'reloading', 'error'ResourceStatus no es un enum TypeScript nativo — es un objeto de constantes (as const), así que se compara con strings literales, no con ResourceStatus.Loading.

    Cuando categoria cambia, Angular cancela el fetch anterior (usando el abortSignal que recibe el loader) y lanza uno nuevo. El ciclo de vida completo, gestionado sin escribir una sola línea de cleanup.

    rxResource(): para servicios que devuelven Observables

    La mayoría de proyectos Angular tienen servicios basados en HttpClient que devuelven Observable. Migrar todo a fetch puro no es viable ni deseable.

    rxResource() es el puente. En lugar de loader, usa stream, que devuelve un Observable.

    import { ChangeDetectionStrategy, Component, signal, inject } from '@angular/core';
    import { rxResource } from '@angular/core/rxjs-interop';
    import { HttpClient } from '@angular/common/http';
    

    interface Producto { id: number; nombre: string; }

    @Component({ selector: 'app-catalogo-rx', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @if (productos.isLoading()) { <p>Cargando...</p> } @else if (productos.hasValue()) { <ul> @for (p of productos.value(); track p.id) { <li>{{ p.nombre }}</li> } </ul> } `, }) export class CatalogoRxComponent { private http = inject(HttpClient); categoria = signal(1);

    productos = rxResource({ params: () => ({ cat: this.categoria() }), stream: ({ params }) => this.http.get<Producto[]>(/api/products?category=${params.cat}), }); }

    Dos puntos que generan confusión frecuente:

    • El import correcto es @angular/core/rxjs-interop, no @angular/core.
    • El método se llama stream, no loader. Los ejemplos de versiones experimentales anteriores usaban loader, de ahí la confusión.

    httpResource(): la opción declarativa

    httpResource() va un paso más allá: elimina la necesidad de declarar un servicio intermedio para casos de fetching simple. Lo declaras directamente en el componente.

    import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
    import { httpResource } from '@angular/common/http';
    

    interface User { id: number; name: string; }

    @Component({ selector: 'app-user-profile', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @if (user.isLoading()) { <p>Cargando...</p> } @else if (user.error()) { <p>Error al cargar el perfil</p> } @else if (user.hasValue()) { <p>{{ user.value()?.name }}</p> } `, }) export class UserProfileComponent { userId = signal(1);

    user = httpResource<User>(() => /api/user/${this.userId()}); }

    httpResource() expone dos signals exclusivos que no tienen resource() ni rxResource():

    • .statusCode() — el código HTTP de la respuesta (200, 404, 500…)
    • .headers() — las cabeceras de la respuesta

    Ambas son señales independientes de .status(), que sigue siendo el estado del ciclo de vida del recurso. Confundir .status() con .statusCode() es el error más frecuente al empezar con esta API.

    Para respuestas que no son JSON:

    // Texto plano
    const readme = httpResource.text(() => /docs/readme.md);
    

    // Binario const avatar = httpResource.blob(() => /api/user/${this.userId()}/avatar);

    Requiere provideHttpClient() en el bootstrap. Usa HttpClient e interceptores por debajo, así que tus interceptores de autenticación siguen funcionando sin cambiar nada.

    Recuerda que httpResource() sigue marcado como experimental en v22. Para proyectos con requisitos estrictos de estabilidad de API, usa rxResource() con tu servicio HttpClient habitual hasta que se estabilice.

    Cuándo usar cada uno

    No es una decisión complicada si tienes claros los criterios:

    | Situación | API recomendada | |—|—| | Fetch puro o API externa directa | resource() | | Tienes servicios con Observable existentes | rxResource() | | Fetching simple sin servicio intermedio (experimental) | httpResource() | | Necesitas el status code HTTP como signal | httpResource() |

    Las tres APIs comparten la misma superficie de lectura: .value(), .isLoading(), .error(), .hasValue(), .status(), .reload(). Cambiar de una a otra es mínimamente invasivo.

    Validación del dato en runtime

    El genérico de TypeScript solo existe en tiempo de compilación. Si el backend devuelve algo inesperado, httpResource() no lanzará ningún error — simplemente tendrás un objeto mal tipado en runtime.

    La opción parse existe exactamente para este caso:

    import { z } from 'zod';
    

    const UserSchema = z.object({ id: z.number(), name: z.string(), });

    user = httpResource( () => /api/user/${this.userId()}, { parse: UserSchema.parse } );

    Si el dato del backend no cumple el schema, el resource entra en estado 'error' automáticamente. Sin try/catch manual, sin runtime silencioso. Si quieres profundizar en cómo construir schemas robustos con Zod para este tipo de validación, el curso de Zod para TypeScript cubre exactamente estos patrones de producción.

    Lo que cambia en tu arquitectura

    La Resource API no elimina los servicios Angular — los reorganiza. Sigues necesitando servicios para encapsular lógica de negocio compleja, componer múltiples endpoints, o compartir estado entre componentes. Lo que elimina es el boilerplate de gestión de ciclo de vida en los componentes que simplemente cargan y muestran datos.

    Un componente que antes necesitaba un servicio, tres operadores RxJS y un takeUntilDestroyed ahora expresa la misma intención en diez líneas. La lógica no desaparece — se mueve al lugar correcto.

    Si quieres el cuadro completo — Signals, Resource API, Signal Forms, Zoneless y todo lo que llegó en v22 — el curso Angular Moderno tiene el módulo M10 dedicado íntegramente a Resource API con ejemplos sobre el proyecto ShopFlow.

    Qué hacer hoy

    Identifica en tu proyecto los componentes que tienen este patrón: signal o BehaviorSubject como parámetro, switchMap hacia HttpClient, y async pipe en el template.

    Esos son tus candidatos para migrar a rxResource(). No necesitas reescribir los servicios. Solo cambias la forma en que el componente consume el Observable.

    Empieza por un componente de solo lectura — uno que carga datos y no tiene formularios complejos. Comprueba que .status() en el template te da todo lo que necesitabas del loading$ que tenías antes.

    Si funciona ahí, tienes el patrón. El resto de la migración es repetirlo.

    Preguntas frecuentes

    ¿Cuál es la diferencia entre resource() y httpResource() en Angular 22? resource() acepta cualquier función que devuelva una Promise — puedes usarlo con fetch, con SDKs externos, o con cualquier operación asíncrona. httpResource() es un wrapper declarativo sobre HttpClient que además expone el status code HTTP y las cabeceras como signals independientes. La diferencia clave: httpResource() sigue siendo experimental en v22; resource() es API estable.

    ¿Puedo usar rxResource() si tengo servicios que devuelven Observables? Sí. rxResource() está diseñado exactamente para ese caso. En lugar de loader, defines un stream que devuelve un Observable. Tus servicios existentes no cambian — solo cambia cómo el componente los consume.

    ¿La Resource API reemplaza completamente RxJS en Angular? No. RxJS sigue siendo útil para transformaciones complejas de streams, operadores avanzados y casos donde necesitas combinar múltiples fuentes. La Resource API reemplaza el patrón subscribe/unsubscribe para carga de datos HTTP en componentes — no todos los casos de uso reactivo.

    ¿Qué ocurre con los datos en caché cuando cambia el signal de parámetros? Cuando el signal de params cambia, el resource entra en estado 'reloading' (no 'loading'). El valor anterior sigue disponible en .value() durante la recarga. Esto permite mostrar datos obsoletos mientras llegan los nuevos, en lugar de mostrar un spinner que vacía la UI. Es el comportamiento por defecto — no necesitas configurarlo.

    ¿Funciona la Resource API con Angular SSR? Sí. httpResource() usa HttpClient internamente, que ya tiene soporte de transferencia de estado para SSR. Con resource() y rxResource() necesitas gestionar tú mismo la transferencia de estado si el servidor precarga datos. La integración más limpia con SSR actualmente es a través de httpResource() o rxResource() con un servicio que use TransferState.

    Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode. Ha migrado proyectos Angular en producción desde v2 hasta v22.

    Sources: