Contenido del curso

Nuevas Funcionalidades en Angular

Optimización de Rendimiento

toSignal: Observables de RxJS como Signals

Resumen

Si tu aplicación Angular está llena de código en RxJS, no necesitas reescribir nada para empezar a usar Signals. La función toSignal te permite convertir cualquier observable en un signal sin tocar la lógica reactiva que ya tienes funcionando en tus servicios.

¿Qué es toSignal y por qué importa en Angular?

Durante años, Angular nos dijo que RxJS era el patrón reactivo del framework. Hoy llegan los Signals, y aunque son un modelo más simple y eficiente, migrar cada BehaviorSubject o Subject sería una locura. Por eso el equipo de Angular creó una vía de interoperabilidad.

toSignal es una función que vive en @angular/core/rxjs-interop y traduce un observable a un signal listo para usarse en componentes. No reemplaza tu código RxJS, lo envuelve.

¿Qué hace exactamente toSignal? Toma un observable como entrada y devuelve un signal que se mantiene sincronizado con cada valor emitido por ese observable. Así puedes usar la nueva reactividad en tus templates sin reescribir servicios.

¿Cómo identifico si mi observable tiene valor inicial o no?

Esta es la pregunta más importante antes de usar toSignal, porque define qué opción debes pasarle. Hay dos familias claras de observables en tu código.

Los que tienen valor inicial: el clásico BehaviorSubject, que se declara con un valor por defecto desde el primer momento.

typescript observableWithInit = new BehaviorSubject<string>('initValue');

Los que no tienen valor inicial: un Subject puro, o cualquier petición HTTP hecha con HttpClient. Estos solo emiten cuando algo o alguien les manda un valor, por ejemplo cuando la API responde.

typescript observableWithoutInit = new Subject<string>();

¿Cuándo uso requireSync y cuándo initialValue?

Un signal siempre necesita un valor inicial, esa es la regla de oro. La diferencia está en de dónde sale ese valor.

  • Si tu observable tiene valor inicial, usa requireSync: true. El signal toma el valor directamente del observable de forma síncrona.
  • Si tu observable no tiene valor inicial, dáselo tú con initialValue. Así el signal arranca con algo mientras espera la primera emisión.

typescript import { toSignal } from '@angular/core/rxjs-interop';

signalWithInit = toSignal(this.observableWithInit, { requireSync: true }); signalWithoutInit = toSignal(this.observableWithoutInit, { initialValue: '---' });

¿Qué pasa si olvido el initialValue en un Subject? Tu signal podría devolver undefined hasta que llegue la primera emisión, lo que rompe los tipos en TypeScript y la lógica de tu template.

¿Cómo verifico que el signal se sincroniza con el observable?

La prueba más simple es emitir nuevos valores desde un botón en el template y ver cómo el signal reacciona en tiempo real. Aquí entra una práctica útil: simular latencia con pipe(delay(3000)) para entender el comportamiento asíncrono.

typescript emitWithInit() { this.observableWithInit.next('newValue'); }

emitWithoutInit() { this.observableWithoutInit.next('***'); }

En el HTML renderizas el signal como cualquier otro: {{ signalWithInit() }}. Cada next() que dispares en el observable se refleja automáticamente en el signal, y por lo tanto en la vista.

¿Qué gano al convertir observables en signals?

La ganancia real es que en tus componentes puedes empezar a usar todo el ecosistema nuevo de reactividad sin botar el trabajo previo.

  • Puedes meter ese signal dentro de un computed() para derivar valores.
  • Puedes combinarlo con otros signals en un effect().
  • Mantienes intacta la lógica de tus servicios, incluyendo llamadas HTTP, streams y operadores RxJS.
  • Tu arquitectura no cambia: solo añades una capa de traducción en el punto de consumo.

Este patrón es especialmente valioso cuando tienes servicios que usan HttpClient, porque cada petición es un observable sin valor inicial por definición. Ahí toSignal con initialValue se vuelve tu mejor aliado.

Conceptos y referencias clave del transcript

Para que el aprendizaje quede anclado, vale la pena explicar los términos que aparecen en la clase y dónde se mencionan.

  • toSignal [2:14]: función de @angular/core/rxjs-interop que convierte un observable en un signal manteniendo la sincronización.
  • BehaviorSubject [2:50]: tipo de observable de RxJS que requiere un valor inicial al instanciarse.
  • Subject [4:10]: observable de RxJS sin valor inicial, emite solo cuando recibe un next().
  • requireSync [3:30]: opción de toSignal que indica que el observable ya tiene un valor disponible de forma síncrona.
  • initialValue [4:40]: opción de toSignal para definir el valor de arranque cuando el observable no lo provee.
  • HttpClient [1:20]: cliente HTTP de Angular cuyas peticiones son observables sin valor inicial, candidatos ideales para toSignal con initialValue.
  • Convención $ al inicio o al final [2:30]: el signo de pesos al final marca un observable, al inicio marca un signal. Una pista visual útil para no confundirlos.

¿Tienes servicios con mucho RxJS que estás pensando migrar? Cuéntame en los comentarios cómo planeas integrar Signals en tu arquitectura actual.