<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Typescripts · DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/typescript/</link><description>Blog de tecnología, programación y electrónica, para compartir conocimientos, experiencias y tutoriales con este apasionante mundo.</description><generator>Hugo</generator><language>es-CO</language><copyright>Copyright © 2026 DacaDev. All rights reserved.</copyright><lastBuildDate>Wed, 24 Jun 2026 00:00:00 -0500</lastBuildDate><atom:link href="https://blog.dacadev.com/typescript/index.xml" rel="self" type="application/rss+xml"/><image><url>https://blog.dacadev.com/images/blog-logo.png</url><title>DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/</link></image><item><title>TypeScript: Depuración de errores y tsconfig.json</title><link>https://blog.dacadev.com/typescript/depuracion-y-tsconfig/</link><pubDate>Wed, 24 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/depuracion-y-tsconfig/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Configura el compilador de TypeScript con tsconfig.json: strict, noImplicitAny, removeComments, sourceMap y salida única para depurar y compilar mejor.</description><media:content url="https://blog.dacadev.com/images/typescript/debugging-tsconfig/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-tsconfigjson-y-para-qué-sirve"&gt;Qué es tsconfig.json y para qué sirve&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#opciones-recomendadas"&gt;Opciones recomendadas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#sourcemap-depurar-el-código-original"&gt;sourceMap: depurar el código original&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#generar-un-único-archivo-de-salida"&gt;Generar un único archivo de salida&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#depurar-errores-con-eficacia"&gt;Depurar errores con eficacia&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Artículo final de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Consolidaremos la configuración del compilador mediante &lt;code&gt;tsconfig.json&lt;/code&gt; y las opciones que facilitan la depuración y mejoran la calidad del código emitido.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El archivo &lt;code&gt;tsconfig.json&lt;/code&gt; es el centro de control del compilador: define cómo TypeScript interpreta, verifica y transforma tu proyecto. Una configuración bien afinada no solo previene errores, sino que mejora la experiencia de depuración y la calidad del JavaScript resultante. Cerremos la serie dominando esta pieza. La referencia completa está en la &lt;a href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html"




 target="_blank"
 


&gt;documentación oficial de tsconfig.json&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="qué-es-tsconfigjson-y-para-qué-sirve"&gt;Qué es tsconfig.json y para qué sirve&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt; declara el comportamiento del compilador para todo el proyecto. Cuando se genera por primera vez, muchas opciones aparecen comentadas, y el valor mostrado en el comentario suele ser el recomendado por defecto.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La presencia de un &lt;code&gt;tsconfig.json&lt;/code&gt; en un directorio marca la raíz de un proyecto TypeScript. Ejecutar &lt;code&gt;tsc&lt;/code&gt; sin argumentos hace que el compilador busque este archivo y compile según sus reglas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="opciones-recomendadas"&gt;Opciones recomendadas&lt;/h2&gt;
&lt;p&gt;Estas opciones de &lt;code&gt;compilerOptions&lt;/code&gt; aportan el mayor valor en un proyecto profesional:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;strict&lt;/code&gt;: activa el conjunto completo de comprobaciones estrictas. Es la opción que más errores previene.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;noImplicitAny&lt;/code&gt;: prohíbe que TypeScript asigne &lt;code&gt;any&lt;/code&gt; de forma implícita cuando no puede inferir un tipo, obligándote a ser explícito.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;removeComments&lt;/code&gt;: elimina los comentarios del JavaScript compilado, produciendo una salida más limpia.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sourceMap&lt;/code&gt;: genera &lt;em&gt;source maps&lt;/em&gt; que enlazan el JavaScript emitido con tu código TypeScript original.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;strict&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;noImplicitAny&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;removeComments&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;sourceMap&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;target&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;es2015&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;commonjs&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;outDir&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;dist&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;include&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;src&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;strict&lt;/code&gt; es en realidad un &lt;em&gt;paraguas&lt;/em&gt; que activa varias comprobaciones, entre ellas &lt;code&gt;noImplicitAny&lt;/code&gt;, &lt;code&gt;strictNullChecks&lt;/code&gt; y &lt;code&gt;strictFunctionTypes&lt;/code&gt;. Habilitarlo desde el primer commit evita una migración costosa cuando el proyecto ya acumuló tipos implícitos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="sourcemap-depurar-el-código-original"&gt;sourceMap: depurar el código original&lt;/h2&gt;
&lt;p&gt;Sin &lt;em&gt;source maps&lt;/em&gt;, cuando depuras en el navegador o en Node solo ves el JavaScript transpilado, que puede diferir notablemente de tu TypeScript. Con &lt;code&gt;sourceMap: true&lt;/code&gt;, el compilador genera archivos &lt;code&gt;.js.map&lt;/code&gt; que permiten al depurador mostrar tu código fuente original, colocar &lt;em&gt;breakpoints&lt;/em&gt; en él e inspeccionar variables con sus nombres reales.&lt;/p&gt;
&lt;p&gt;Esta opción es la diferencia entre depurar el código que escribiste y depurar el código que la máquina generó.&lt;/p&gt;
&lt;h2 id="generar-un-único-archivo-de-salida"&gt;Generar un único archivo de salida&lt;/h2&gt;
&lt;p&gt;Para ciertos escenarios —especialmente proyectos de frontend sin un &lt;em&gt;bundler&lt;/em&gt;— resulta útil concatenar toda la salida en un solo archivo JavaScript. Esto se logra con la opción &lt;code&gt;outFile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;outFile&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;./main.js&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;sourceMap&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;removeComments&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;outFile&lt;/code&gt; solo funciona con los sistemas de módulos &lt;code&gt;amd&lt;/code&gt; y &lt;code&gt;system&lt;/code&gt;; no es compatible con &lt;code&gt;commonjs&lt;/code&gt; ni &lt;code&gt;esnext&lt;/code&gt;. En proyectos modernos, lo habitual es delegar el empaquetado a herramientas como webpack o esbuild en lugar de usar &lt;code&gt;outFile&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="depurar-errores-con-eficacia"&gt;Depurar errores con eficacia&lt;/h2&gt;
&lt;p&gt;El flujo de depuración en TypeScript combina las opciones anteriores con la lectura disciplinada de los mensajes del compilador:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cada error incluye un &lt;strong&gt;código&lt;/strong&gt; (por ejemplo &lt;code&gt;TS2345&lt;/code&gt;) que puedes buscar para entender su causa raíz.&lt;/li&gt;
&lt;li&gt;Con &lt;code&gt;strict&lt;/code&gt; activo, los errores afloran en compilación, antes de ejecutar el código.&lt;/li&gt;
&lt;li&gt;Con &lt;code&gt;sourceMap&lt;/code&gt;, los errores en tiempo de ejecución apuntan a tu TypeScript original, no al JavaScript emitido.&lt;/li&gt;
&lt;li&gt;El modo observador (&lt;code&gt;tsc --watch&lt;/code&gt;) reporta los errores de forma incremental mientras escribes.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[Código TS] --&gt; B[tsc con strict]
 B -- error de tipo --&gt; C[Mensaje TSxxxx&lt;br/&gt;en compilación]
 B -- ok --&gt; D[JS + sourceMap]
 D --&gt; E[Runtime]
 E -- error --&gt; F[Stack trace sobre TS&lt;br/&gt;gracias al sourceMap]
&lt;/pre&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tsconfig.json&lt;/code&gt; es la herramienta que transforma TypeScript de un transpilador genérico en un compilador afinado a tu proyecto. Activar &lt;code&gt;strict&lt;/code&gt; y &lt;code&gt;noImplicitAny&lt;/code&gt; maximiza la detección temprana de errores; &lt;code&gt;sourceMap&lt;/code&gt; hace que la depuración opere sobre tu código real; y &lt;code&gt;removeComments&lt;/code&gt; pule la salida. Dominar estas opciones cierra el ciclo: del tipado en el editor a la depuración en producción.&lt;/p&gt;
&lt;p&gt;Con esto concluye la serie sobre TypeScript. Has recorrido desde la instalación y los tipos básicos hasta los genéricos, los decoradores y la configuración del compilador: el conjunto de herramientas necesario para construir aplicaciones robustas y mantenibles con tipado estático.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Namespaces, módulos e importaciones</title><link>https://blog.dacadev.com/typescript/namespaces-y-modulos/</link><pubDate>Tue, 23 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/namespaces-y-modulos/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Organiza tu código en TypeScript con namespaces y módulos ES: exportaciones nombradas, import, alias, export default y archivos barrel con index.ts.</description><media:content url="https://blog.dacadev.com/images/typescript/namespaces-modules/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#namespaces"&gt;Namespaces&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#módulos-export-e-import"&gt;Módulos: export e import&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#archivos-barrel-centralizar-exportaciones"&gt;Archivos barrel: centralizar exportaciones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#export-alias"&gt;Export alias&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#export-default"&gt;Export default&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#del-código-a-un-bundle"&gt;Del código a un bundle&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Décimo artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Organizaremos el código con namespaces y módulos ES: exportaciones nombradas, &lt;code&gt;import&lt;/code&gt;, alias, &lt;code&gt;export default&lt;/code&gt; y archivos &lt;em&gt;barrel&lt;/em&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A medida que un proyecto crece, la organización del código deja de ser un detalle estético para convertirse en un factor de mantenibilidad. TypeScript ofrece dos mecanismos para estructurar el código: los &lt;strong&gt;namespaces&lt;/strong&gt; —agrupadores internos— y los &lt;strong&gt;módulos ES&lt;/strong&gt; —el estándar moderno basado en &lt;code&gt;export&lt;/code&gt; e &lt;code&gt;import&lt;/code&gt;. Analicemos cuándo usar cada uno.&lt;/p&gt;
&lt;h2 id="namespaces"&gt;Namespaces&lt;/h2&gt;
&lt;p&gt;Un namespace agrupa funciones, clases y variables relacionadas bajo un identificador común, exponiendo solo lo que marques con &lt;code&gt;export&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;namespace&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Validations&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;validateText&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;text&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;boolean&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;text&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;length&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;validateDate&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;myDate&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Date&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;boolean&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;isNaN&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;myDate&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;valueOf&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;Validations&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;validateText&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola mundo&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Solo los miembros exportados (&lt;code&gt;validateText&lt;/code&gt;, &lt;code&gt;validateDate&lt;/code&gt;) son accesibles desde fuera mediante la notación &lt;code&gt;Namespace.miembro&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los namespaces se usan cada vez menos en el desarrollo de aplicaciones, donde los módulos ES son el estándar. Sin embargo, siguen presentes como base interna de muchos frameworks y de archivos de definición de tipos (&lt;code&gt;.d.ts&lt;/code&gt;).&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="módulos-export-e-import"&gt;Módulos: export e import&lt;/h2&gt;
&lt;p&gt;Los módulos son el mecanismo recomendado. Cada archivo es un módulo y expone su API con &lt;code&gt;export&lt;/code&gt;; otros archivos la consumen con &lt;code&gt;import&lt;/code&gt;. Para exportar, antepón &lt;code&gt;export&lt;/code&gt; a la declaración:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// classes/Heros.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;powerID&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Y para consumirla, usa &lt;code&gt;import&lt;/code&gt; con desestructuración de los miembros nombrados:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// index.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./classes/Heros&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;spiderman&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Spiderman&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;100&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;23&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="archivos-barrel-centralizar-exportaciones"&gt;Archivos barrel: centralizar exportaciones&lt;/h2&gt;
&lt;p&gt;Cuando una carpeta agrupa varios módulos relacionados, importarlos uno a uno desde rutas distintas se vuelve tedioso. Un archivo &lt;em&gt;barrel&lt;/em&gt; —convencionalmente un &lt;code&gt;index.ts&lt;/code&gt; dentro de la carpeta— reexporta todo desde un único punto de entrada:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// interfaces/index.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./hero&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Villain&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./villain&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esto permite importar múltiples miembros refiriéndote solo a la carpeta, lo que simplifica las rutas y desacopla a los consumidores de la estructura interna:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Villain&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./interfaces&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;flowchart LR
 H[hero.ts] --&gt; I[index.ts barrel]
 V[villain.ts] --&gt; I
 I --&gt; C[consumidor: import desde './interfaces']
&lt;/pre&gt;

&lt;h2 id="export-alias"&gt;Export alias&lt;/h2&gt;
&lt;p&gt;Un alias renombra un miembro al importarlo, lo que resuelve colisiones de nombres entre módulos distintos. Se usa la palabra clave &lt;code&gt;as&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;poderes&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./data/powers&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;poderes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="export-default"&gt;Export default&lt;/h2&gt;
&lt;p&gt;Una exportación por defecto designa el valor principal de un módulo. Se importa sin llaves y puede combinarse con importaciones nombradas en la misma línea:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// data/powers.ts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;default&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Powers&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;/* ... */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;fuerza&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;velocidad&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Powers&lt;/span&gt;, { &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;poderes&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;./data/powers&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Powers&lt;/code&gt; corresponde a la exportación por defecto y &lt;code&gt;poderes&lt;/code&gt; a una exportación nombrada renombrada con alias.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Prefiere las exportaciones nombradas frente a &lt;code&gt;export default&lt;/code&gt; en bases de código grandes: facilitan el &lt;em&gt;autocompletado&lt;/em&gt;, el &lt;em&gt;refactoring&lt;/em&gt; automático y mantienen nombres consistentes entre el módulo y sus consumidores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="del-código-a-un-bundle"&gt;Del código a un bundle&lt;/h2&gt;
&lt;p&gt;Los módulos resuelven la organización en tiempo de desarrollo, pero el navegador necesita servir el resultado de forma eficiente. Empaquetadores como &lt;strong&gt;webpack&lt;/strong&gt; combinan todos los módulos en uno o pocos archivos optimizados, resolviendo el grafo de dependencias que tejen tus &lt;code&gt;import&lt;/code&gt;. TypeScript se integra en este flujo transpilando primero a JavaScript y dejando que el bundler se encargue del empaquetado final.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Estructurar el código es una decisión de arquitectura. Los namespaces agrupan elementos internos y persisten en definiciones de tipos, pero el estándar moderno son los módulos ES con &lt;code&gt;export&lt;/code&gt;/&lt;code&gt;import&lt;/code&gt;. Los archivos &lt;em&gt;barrel&lt;/em&gt; centralizan las exportaciones, los alias resuelven colisiones de nombres y &lt;code&gt;export default&lt;/code&gt; designa el valor principal de un módulo.&lt;/p&gt;
&lt;p&gt;En el artículo final de la serie consolidaremos la configuración del compilador y la &lt;strong&gt;depuración de errores&lt;/strong&gt; mediante &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Decoradores y metaprogramación</title><link>https://blog.dacadev.com/typescript/decoradores/</link><pubDate>Mon, 22 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/decoradores/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a usar decoradores en TypeScript: decoradores de clase, de fábrica, de método y de propiedad para extender comportamiento con metaprogramación.</description><media:content url="https://blog.dacadev.com/images/typescript/decorators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#decoradores-de-clase"&gt;Decoradores de clase&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#decoradores-de-fábrica"&gt;Decoradores de fábrica&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#decoradores-de-método"&gt;Decoradores de método&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#decoradores-de-propiedad"&gt;Decoradores de propiedad&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Noveno artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Estudiaremos los decoradores: funciones que se ejecutan en la definición de clases, métodos y propiedades para extender su comportamiento sin modificar su código original.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Un &lt;strong&gt;decorador en TypeScript&lt;/strong&gt; es una función que se ejecuta en tiempo de transpilación y permite expandir la funcionalidad de un objeto —clase, método o propiedad— de forma declarativa. Frameworks como Angular o NestJS apoyan gran parte de su ergonomía en este mecanismo. Analicemos cada variante con ejemplos prácticos. Puedes consultar la referencia completa en la &lt;a href="https://www.typescriptlang.org/docs/handbook/decorators.html"




 target="_blank"
 


&gt;documentación oficial de decoradores&lt;/a&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los decoradores se colocan con la sintaxis &lt;code&gt;@nombre&lt;/code&gt; justo antes del elemento a decorar. Por convención se declaran con &lt;code&gt;function&lt;/code&gt; —en lugar de arrow functions— para distinguirlos visualmente de las funciones ordinarias.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="decoradores-de-clase"&gt;Decoradores de clase&lt;/h2&gt;
&lt;p&gt;Un decorador de clase recibe el constructor y se ejecuta &lt;strong&gt;una sola vez&lt;/strong&gt;, en el momento en que se define la clase —no al crear cada instancia:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;printToConsole&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Function&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;@printToConsole&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Pokemon&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;publicApi&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://pokeapi.co&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al crear varias instancias, el decorador no vuelve a ejecutarse: su efecto ocurre en la definición, no en la instanciación.&lt;/p&gt;
&lt;h2 id="decoradores-de-fábrica"&gt;Decoradores de fábrica&lt;/h2&gt;
&lt;p&gt;Un decorador de fábrica es una función que &lt;strong&gt;retorna&lt;/strong&gt; el decorador real. Esto permite parametrizar el comportamiento, aceptando argumentos que controlan cómo se aplica:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;printToConsole&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Function&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;printToConsoleConditional&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;print&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Function&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;print&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#e06c75"&gt;printToConsole&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;@printToConsoleConditional&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Pokemon&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;publicApi&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://pokeapi.co&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un patrón habitual es sellar el prototipo para impedir que se alteren sus propiedades en tiempo de ejecución:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;blockPrototype&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Function&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;Object&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;seal&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;Object&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;seal&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;prototype&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;@blockPrototype&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;@printToConsoleConditional&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Pokemon&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Cuando aplicas múltiples decoradores, se ejecutan de forma secuencial &lt;strong&gt;de abajo hacia arriba&lt;/strong&gt;. En el ejemplo anterior, primero corre &lt;code&gt;printToConsoleConditional&lt;/code&gt; y luego &lt;code&gt;blockPrototype&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="decoradores-de-método"&gt;Decoradores de método&lt;/h2&gt;
&lt;p&gt;Un decorador de método recibe tres argumentos —el objeto al que pertenece, el nombre del método y su &lt;code&gt;PropertyDescriptor&lt;/code&gt;— y puede inspeccionar o &lt;strong&gt;reemplazar&lt;/strong&gt; por completo el comportamiento del método. Aquí lo usamos para validar argumentos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CheckValidPokemonId() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;target&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;any&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;propertyKey&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;descriptor&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;PropertyDescriptor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;originalMethod&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;descriptor&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;descriptor&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;id&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;||&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#d19a66"&gt;100&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;El id del pokemon debe estar entre 1 y 100&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;originalMethod&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Pokemon&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;publicApi&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://pokeapi.co&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;@CheckValidPokemonId&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;savePokemonToDB&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`Pokemon guardado en la base de datos &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al envolver &lt;code&gt;originalMethod&lt;/code&gt;, el decorador intercepta la llamada, valida el &lt;code&gt;id&lt;/code&gt; y solo delega al método original cuando el valor es válido. Este es el fundamento de las validaciones declarativas de muchos frameworks.&lt;/p&gt;
&lt;h2 id="decoradores-de-propiedad"&gt;Decoradores de propiedad&lt;/h2&gt;
&lt;p&gt;Un decorador de propiedad recibe el objeto y el nombre de la propiedad, y puede alterar cómo se lee y escribe. Es útil para controlar el acceso a datos —recordando que JavaScript no tiene propiedades verdaderamente privadas en runtime:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;readOnly&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;isWriteable&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Function&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;any&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;propertyKey&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;descriptor&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;PropertyDescriptor&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;get&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Daca code&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;set&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;val&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;Object&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;propertyKey&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;val&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;writable&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;isWriteable&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;enumerable&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;descriptor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Pokemon&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;@readOnly&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;publicApi&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://pokeapi.co&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El decorador define un &lt;code&gt;get&lt;/code&gt;/&lt;code&gt;set&lt;/code&gt; personalizado que gobierna por completo el acceso a &lt;code&gt;publicApi&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los decoradores aportan metaprogramación declarativa a TypeScript: el decorador de clase actúa sobre el constructor una única vez, el de fábrica parametriza el comportamiento, el de método intercepta y reemplaza llamadas, y el de propiedad controla la lectura y escritura. Componerlos en cadena —respetando su orden de ejecución— es lo que habilita las APIs elegantes de frameworks modernos.&lt;/p&gt;
&lt;p&gt;En el próximo artículo organizaremos el código con &lt;strong&gt;namespaces y módulos&lt;/strong&gt;: &lt;code&gt;export&lt;/code&gt;, &lt;code&gt;import&lt;/code&gt;, alias y exportaciones por defecto.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Tipos avanzados, subtipos y varianza</title><link>https://blog.dacadev.com/typescript/tipos-avanzados/</link><pubDate>Sun, 21 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/tipos-avanzados/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Comprende la jerarquía de tipos de TypeScript: subtipos y supertipos, los tipos top y bottom (unknown y never), null, undefined, void y la varianza.</description><media:content url="https://blog.dacadev.com/images/typescript/advanced-types/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#subtipos"&gt;Subtipos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#supertipos"&gt;Supertipos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-jerarquía-de-tipos"&gt;La jerarquía de tipos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#los-tipos-especiales-null-undefined-void-y-never"&gt;Los tipos especiales: null, undefined, void y never&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#varianza"&gt;Varianza&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Octavo artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Abordaremos la teoría que sustenta el sistema de tipos: subtipos, supertipos, la jerarquía completa, los tipos &lt;code&gt;unknown&lt;/code&gt; y &lt;code&gt;never&lt;/code&gt;, y la varianza.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Comprender la &lt;strong&gt;relación entre tipos&lt;/strong&gt; es lo que separa a quien usa TypeScript de quien lo domina. El compilador decide qué asignaciones son válidas aplicando reglas de subtipado y varianza. Una vez interiorizadas estas reglas, los errores del typechecker dejan de ser obstáculos crípticos y se convierten en información precisa sobre el diseño de tus tipos.&lt;/p&gt;
&lt;h2 id="subtipos"&gt;Subtipos&lt;/h2&gt;
&lt;p&gt;La regla fundamental del subtipado se enuncia así:&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si tienes un tipo &lt;code&gt;A&lt;/code&gt; y un tipo &lt;code&gt;B&lt;/code&gt; donde &lt;code&gt;B&lt;/code&gt; es &lt;strong&gt;subtipo&lt;/strong&gt; de &lt;code&gt;A&lt;/code&gt;, entonces puedes usar &lt;code&gt;B&lt;/code&gt; en cualquier lugar donde se espere un &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Algunas relaciones de subtipo en TypeScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Array&lt;/code&gt; es subtipo de &lt;code&gt;Object&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Tuple&lt;/code&gt; es subtipo de &lt;code&gt;Array&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Todo es subtipo de &lt;code&gt;any&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;never&lt;/code&gt; es subtipo de todo.&lt;/li&gt;
&lt;li&gt;Si una clase &lt;code&gt;Bird&lt;/code&gt; extiende &lt;code&gt;Animal&lt;/code&gt;, entonces &lt;code&gt;Bird&lt;/code&gt; es subtipo de &lt;code&gt;Animal&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aplicado a la práctica, esto significa que donde se necesite un &lt;code&gt;Object&lt;/code&gt; puedes usar un &lt;code&gt;Array&lt;/code&gt;; donde se necesite un &lt;code&gt;Array&lt;/code&gt; puedes usar una &lt;code&gt;Tuple&lt;/code&gt;; y donde se necesite un &lt;code&gt;Animal&lt;/code&gt; puedes usar un &lt;code&gt;Bird&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="supertipos"&gt;Supertipos&lt;/h2&gt;
&lt;p&gt;Un supertipo es la relación inversa:&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si tienes un tipo &lt;code&gt;A&lt;/code&gt; y un tipo &lt;code&gt;B&lt;/code&gt; donde &lt;code&gt;B&lt;/code&gt; es &lt;strong&gt;supertipo&lt;/strong&gt; de &lt;code&gt;A&lt;/code&gt;, entonces puedes usar &lt;code&gt;A&lt;/code&gt; en cualquier lugar donde se espere un &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Las relaciones de supertipo reflejan en espejo a las anteriores:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Array&lt;/code&gt; es supertipo de &lt;code&gt;Tuple&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Object&lt;/code&gt; es supertipo de &lt;code&gt;Array&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;any&lt;/code&gt; es supertipo de todo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Animal&lt;/code&gt; es supertipo de &lt;code&gt;Bird&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="la-jerarquía-de-tipos"&gt;La jerarquía de tipos&lt;/h2&gt;
&lt;p&gt;Todas estas relaciones forman una jerarquía con un tipo en la cúspide (&lt;em&gt;top type&lt;/em&gt;) y otro en el fondo (&lt;em&gt;bottom type&lt;/em&gt;):&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 Unknown[unknown - top type] --&gt; Any[any]
 Any --&gt; Number
 Any --&gt; BigInt
 Any --&gt; Boolean
 Any --&gt; String
 Any --&gt; Symbol
 Any --&gt; Object
 Any --&gt; Void
 Any --&gt; Null
 Any --&gt; Undefined
 Object --&gt; Array
 Array --&gt; Tuple
 Object --&gt; Function
 Number --&gt; Never[never - bottom type]
 String --&gt; Never
 Boolean --&gt; Never
 Object --&gt; Never
 Tuple --&gt; Never
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;unknown&lt;/code&gt;&lt;/strong&gt; es el &lt;em&gt;top type&lt;/em&gt;: todo es asignable a él, pero no permite operar sin acotar primero.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;never&lt;/code&gt;&lt;/strong&gt; es el &lt;em&gt;bottom type&lt;/em&gt;: es subtipo de cualquier otro tipo y representa lo que nunca ocurre.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="los-tipos-especiales-null-undefined-void-y-never"&gt;Los tipos especiales: null, undefined, void y never&lt;/h2&gt;
&lt;p&gt;Estos cuatro tipos modelan la ausencia de valor con matices distintos:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Tipo&lt;/th&gt;
 &lt;th&gt;Significado&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Ausencia explícita de valor&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;undefined&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Variable que aún no recibió un valor&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;void&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Función que no tiene sentencia &lt;code&gt;return&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;never&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Función que nunca retorna&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;La distinción entre &lt;code&gt;void&lt;/code&gt; y &lt;code&gt;never&lt;/code&gt; es sutil pero importante. Una función &lt;code&gt;void&lt;/code&gt; termina sin devolver nada útil; una función &lt;code&gt;never&lt;/code&gt; no termina en absoluto, ya sea porque lanza una excepción o porque entra en un bucle infinito:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// void: termina, no retorna valor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// never: nunca completa su ejecución
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fail&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;never&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;throw&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Error&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;loopForever&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;never&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;while&lt;/span&gt; (&lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;never&lt;/code&gt; es especialmente útil en la verificación de exhaustividad: si un &lt;code&gt;switch&lt;/code&gt; cubre todos los casos de una unión, la rama &lt;code&gt;default&lt;/code&gt; puede asignar el valor a un &lt;code&gt;never&lt;/code&gt;, y el compilador detectará en tiempo de compilación cualquier caso olvidado al ampliar la unión.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="varianza"&gt;Varianza&lt;/h2&gt;
&lt;p&gt;Determinar si un tipo es sub o supertipo de otro no siempre es evidente, sobre todo al combinar estructuras y funciones. TypeScript dispone de una notación formal para razonar sobre estas relaciones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;A &amp;lt;: B&lt;/code&gt; significa &amp;ldquo;&lt;code&gt;A&lt;/code&gt; es subtipo de, o el mismo tipo que, &lt;code&gt;B&lt;/code&gt;&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;A &amp;gt;: B&lt;/code&gt; significa &amp;ldquo;&lt;code&gt;A&lt;/code&gt; es supertipo de, o el mismo tipo que, &lt;code&gt;B&lt;/code&gt;&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La &lt;strong&gt;varianza&lt;/strong&gt; describe cómo se propagan estas relaciones cuando los tipos se anidan en estructuras (arreglos, objetos) o en firmas de función. Es el motivo por el que, por ejemplo, un arreglo de un subtipo no siempre es intercambiable con un arreglo de su supertipo: la mutabilidad introduce restricciones que el compilador debe respetar para mantener la solidez del sistema.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;El sistema de tipos de TypeScript es una jerarquía gobernada por reglas de subtipado y varianza, con &lt;code&gt;unknown&lt;/code&gt; como tipo superior y &lt;code&gt;never&lt;/code&gt; como tipo inferior. Distinguir &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;void&lt;/code&gt; y &lt;code&gt;never&lt;/code&gt;, y comprender cómo &lt;code&gt;B &amp;lt;: A&lt;/code&gt; permite sustituir un tipo por otro, te da una intuición precisa de por qué el compilador acepta o rechaza una asignación.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo aplicaremos metaprogramación con &lt;strong&gt;decoradores&lt;/strong&gt;, funciones que extienden el comportamiento de clases, métodos y propiedades.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Genéricos y código reutilizable</title><link>https://blog.dacadev.com/typescript/genericos/</link><pubDate>Sat, 20 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/genericos/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a usar genéricos en TypeScript para escribir funciones y clases reutilizables que preservan la seguridad de tipos con parámetros de tipo dinámicos.</description><media:content url="https://blog.dacadev.com/images/typescript/generics/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#funciones-genéricas"&gt;Funciones genéricas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#por-qué-no-basta-con-any"&gt;Por qué no basta con any&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#clases-genéricas"&gt;Clases genéricas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#restringir-genéricos-con-extends"&gt;Restringir genéricos con extends&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Séptimo artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Exploraremos los genéricos: funciones y clases que operan sobre tipos dinámicos sin renunciar a la verificación estática.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Los &lt;strong&gt;genéricos en TypeScript&lt;/strong&gt; resuelven una tensión recurrente: escribir código reutilizable que funcione con cualquier tipo, pero sin caer en &lt;code&gt;any&lt;/code&gt; y perder toda la seguridad. Un genérico introduce un &lt;em&gt;parámetro de tipo&lt;/em&gt; —una variable que representa un tipo aún por determinar— que se resuelve en el momento de uso. Analicemos cómo aplicarlos.&lt;/p&gt;
&lt;h2 id="funciones-genéricas"&gt;Funciones genéricas&lt;/h2&gt;
&lt;p&gt;Una función genérica declara su parámetro de tipo con la sintaxis &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt; antes de la lista de parámetros. &lt;code&gt;T&lt;/code&gt; representa el tipo que recibirá, y la función puede usarlo para tipar argumentos y retorno:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Función tradicional
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;genericFunction&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;argumento&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;T&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;argumento&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Arrow function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;export&lt;/span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;genericArrowFunction&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;argumento&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;T&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;argumento&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La función anterior retorna exactamente el mismo tipo que recibe. Si la invocas con un &lt;code&gt;string&lt;/code&gt;, TypeScript sabe que el retorno es &lt;code&gt;string&lt;/code&gt;; si la invocas con un &lt;code&gt;number&lt;/code&gt;, el retorno es &lt;code&gt;number&lt;/code&gt;. Esto es lo que distingue a un genérico de &lt;code&gt;any&lt;/code&gt;: &lt;strong&gt;la relación entre entrada y salida se preserva&lt;/strong&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;T&lt;/code&gt; es el nombre convencional, pero es arbitrario. Para múltiples parámetros suelen usarse &lt;code&gt;T&lt;/code&gt;, &lt;code&gt;U&lt;/code&gt;, &lt;code&gt;K&lt;/code&gt;, &lt;code&gt;V&lt;/code&gt;, o nombres descriptivos como &lt;code&gt;TItem&lt;/code&gt; cuando aportan claridad.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-no-basta-con-any"&gt;Por qué no basta con any&lt;/h2&gt;
&lt;p&gt;Comparemos las dos aproximaciones para entender el valor de los genéricos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Con any: se pierde la información de tipo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;identityAny&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;arg&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;any&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;any&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;arg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;identityAny&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// a es any → sin autocompletado ni verificación
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Con genéricos: el tipo se conserva
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;identity&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;arg&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;T&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;arg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;identity&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// b es string → seguridad completa
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con &lt;code&gt;any&lt;/code&gt;, el resultado pierde todo su tipo y el typechecker deja de ayudar. Con un genérico, la firma encadena el tipo de entrada con el de salida.&lt;/p&gt;
&lt;h2 id="clases-genéricas"&gt;Clases genéricas&lt;/h2&gt;
&lt;p&gt;Las clases también admiten parámetros de tipo, lo que permite construir estructuras de datos reutilizables y type-safe. El parámetro se declara junto al nombre de la clase y queda disponible en todos sus miembros:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;MyMap&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;V&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;initialKey&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;initialValue&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;V&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;get&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;K&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;V&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;set&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;V&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;static&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;V&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;k&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;v&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;V&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;MyMap&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;K&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;V&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al instanciarla, los tipos pueden indicarse explícitamente o inferirse de los argumentos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;MyMap&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;k&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// MyMap&amp;lt;string, number&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;MyMap&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;k&amp;#39;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// MyMap&amp;lt;string, boolean&amp;gt; (inferido)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;k&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;set&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;k&amp;#39;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;flowchart LR
 G["MyMap&amp;lt;K, V&amp;gt;"] --&gt; A["MyMap&amp;lt;string, number&amp;gt;"]
 G --&gt; B["MyMap&amp;lt;string, boolean&amp;gt;"]
 G --&gt; C["MyMap&amp;lt;number, Hero&amp;gt;"]
&lt;/pre&gt;

&lt;p&gt;Una sola definición genérica genera tantas variantes type-safe como combinaciones de tipos uses.&lt;/p&gt;
&lt;h2 id="restringir-genéricos-con-extends"&gt;Restringir genéricos con extends&lt;/h2&gt;
&lt;p&gt;A veces un genérico no debe aceptar cualquier tipo, sino solo aquellos que cumplan cierta forma. La cláusula &lt;code&gt;extends&lt;/code&gt; impone esa restricción y, a la vez, habilita el acceso seguro a los miembros garantizados:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getLength&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt; &lt;span style="color:#e06c75"&gt;extends&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;length&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;number&lt;/span&gt; }&amp;gt;(&lt;span style="color:#e06c75"&gt;item&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;item&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;getLength&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// OK: string tiene length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;getLength&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]) &lt;span style="color:#7f848e"&gt;// OK: array tiene length
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;getLength&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;42&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// Error: number no tiene &amp;#39;length&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;T extends { length: number }&lt;/code&gt; restringe &lt;code&gt;T&lt;/code&gt; a tipos que posean una propiedad &lt;code&gt;length&lt;/code&gt;, permitiendo usarla con seguridad dentro de la función.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los genéricos son la herramienta que permite escribir código verdaderamente reutilizable sin sacrificar la verificación de tipos. Las funciones genéricas encadenan el tipo de entrada con el de salida, las clases genéricas habilitan estructuras de datos type-safe, y las restricciones con &lt;code&gt;extends&lt;/code&gt; acotan los tipos aceptados mientras exponen sus miembros de forma segura.&lt;/p&gt;
&lt;p&gt;En el próximo artículo abordaremos los &lt;strong&gt;tipos avanzados&lt;/strong&gt;: subtipos, supertipos, varianza y la jerarquía completa del sistema de tipos.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Clases, herencia y patrones de diseño</title><link>https://blog.dacadev.com/typescript/clases-e-interfaces/</link><pubDate>Fri, 19 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/clases-e-interfaces/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Domina las clases en TypeScript: herencia, modificadores public/protected/private, clases abstractas, getters/setters, estáticos y patrones Factory y Builder.</description><media:content url="https://blog.dacadev.com/images/typescript/classes-inheritance/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#clases-y-herencia"&gt;Clases y herencia&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#modificadores-de-acceso"&gt;Modificadores de acceso&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#clases-abstractas"&gt;Clases abstractas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#super-invocar-a-la-clase-padre"&gt;super: invocar a la clase padre&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#getters-y-setters"&gt;Getters y setters&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#miembros-estáticos"&gt;Miembros estáticos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#this-como-tipo-de-retorno"&gt;this como tipo de retorno&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipado-estructural"&gt;Tipado estructural&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#constructor-privado"&gt;Constructor privado&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#patrones-de-diseño-habilitados"&gt;Patrones de diseño habilitados&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#factory-pattern"&gt;Factory Pattern&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#builder-pattern"&gt;Builder Pattern&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Sexto artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Recorreremos las clases: herencia, modificadores de acceso, clases abstractas, &lt;code&gt;super&lt;/code&gt;, getters/setters, miembros estáticos, tipado estructural y los patrones de diseño que habilitan.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Las &lt;strong&gt;clases en TypeScript&lt;/strong&gt; parten de la sintaxis de JavaScript y la enriquecen con modificadores de acceso, clases abstractas y tipado estructural. El resultado es un modelo de orientación a objetos cercano al de lenguajes como C++ o Java, pero que compila a JavaScript estándar. Analicemos sus capacidades.&lt;/p&gt;
&lt;h2 id="clases-y-herencia"&gt;Clases y herencia&lt;/h2&gt;
&lt;p&gt;La declaración usa &lt;code&gt;class&lt;/code&gt; y la herencia se establece con &lt;code&gt;extends&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Piece&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;King&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Piece&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Queen&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Piece&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Bishop&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Piece&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Podemos restringir los atributos a valores concretos combinando clases con tipos literales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Color&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Black&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;White&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;File&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;B&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;C&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;D&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;E&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;F&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;G&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Rank&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;4&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;5&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;6&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;7&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#d19a66"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Position&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;file&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;File&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;rank&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Rank&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Declarar los parámetros del constructor con un modificador (&lt;code&gt;private file: File&lt;/code&gt;) es un atajo: TypeScript crea y asigna la propiedad automáticamente, evitando el habitual &lt;code&gt;this.file = file&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="modificadores-de-acceso"&gt;Modificadores de acceso&lt;/h2&gt;
&lt;p&gt;TypeScript define tres niveles de visibilidad para atributos y métodos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt;: accesible desde cualquier lugar. Es el nivel por defecto.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;protected&lt;/code&gt;: accesible desde la propia clase y sus subclases.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt;: accesible únicamente desde la propia clase.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;team&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;realName?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;bio() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;team&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;bioInterno() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;team&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;private&lt;/code&gt; y &lt;code&gt;protected&lt;/code&gt; solo aplican en tiempo de compilación. El JavaScript emitido no impide el acceso en runtime; para privacidad real en ejecución usa los campos privados nativos de JavaScript (&lt;code&gt;#campo&lt;/code&gt;).&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="clases-abstractas"&gt;Clases abstractas&lt;/h2&gt;
&lt;p&gt;Una clase &lt;code&gt;abstract&lt;/code&gt; define una plantilla que no puede instanciarse, pero sirve de esqueleto para sus subclases. Puede declarar miembros concretos y miembros &lt;code&gt;abstract&lt;/code&gt; que las subclases están obligadas a implementar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;abstract&lt;/span&gt; &lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Mutante&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Mutante&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saveWorld() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Mundo salvado&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Villano&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Mutante&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;conquistWorld() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Mundo conquistado&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wolverine&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Wolverine&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;Logan&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;magneto&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Villano&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Magneto&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;Magnus&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Una ventaja adicional: una función puede aceptar cualquier objeto que herede de la clase abstracta, lo que habilita el polimorfismo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;printName&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;character&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Mutante&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;character&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;printName&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;wolverine&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;printName&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;magneto&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="super-invocar-a-la-clase-padre"&gt;super: invocar a la clase padre&lt;/h2&gt;
&lt;p&gt;Cuando una subclase sobrescribe un método del padre, puede invocar la versión original con &lt;code&gt;super.metodo()&lt;/code&gt;. Si la subclase define un constructor, &lt;strong&gt;debe&lt;/strong&gt; llamar a &lt;code&gt;super()&lt;/code&gt; para inicializar correctamente la cadena de herencia:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;isMutant&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;super&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getFullNameDesdeXmen() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;super&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getFullName&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="getters-y-setters"&gt;Getters y setters&lt;/h2&gt;
&lt;p&gt;Los &lt;em&gt;accessors&lt;/em&gt; exponen métodos que se comportan sintácticamente como atributos, facilitando la lectura y asignación controladas:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;get&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fullName() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; - &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;set&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fullName&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;realName&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wolverine&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Wolverine&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;Logan&amp;#39;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;wolverine&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;fullName&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// se lee como atributo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;wolverine&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;fullName&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// se asigna como atributo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="miembros-estáticos"&gt;Miembros estáticos&lt;/h2&gt;
&lt;p&gt;Los miembros &lt;code&gt;static&lt;/code&gt; pertenecen a la clase, no a sus instancias:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;static&lt;/span&gt; &lt;span style="color:#e06c75"&gt;avgAge&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;static&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getAvgAge() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;avgAge&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;avgAge&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// se accede vía la clase
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="this-como-tipo-de-retorno"&gt;this como tipo de retorno&lt;/h2&gt;
&lt;p&gt;Cuando un método retorna la propia instancia, su tipo de retorno es &lt;code&gt;this&lt;/code&gt;. Esto es la base del encadenamiento de métodos (&lt;em&gt;method chaining&lt;/em&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Set&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="tipado-estructural"&gt;Tipado estructural&lt;/h2&gt;
&lt;p&gt;TypeScript verifica las clases por &lt;strong&gt;estructura&lt;/strong&gt;, no por nombre. Dos tipos compatibles en forma son intercambiables, con una salvedad: los miembros &lt;code&gt;private&lt;/code&gt; rompen la compatibilidad estructural:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;x&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt; {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;f&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;A&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;f&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt;()) &lt;span style="color:#7f848e"&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;f&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt;()) &lt;span style="color:#7f848e"&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;f&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt; }) &lt;span style="color:#7f848e"&gt;// Error TS2345: &amp;#39;x&amp;#39; es private en &amp;#39;A&amp;#39; pero no en &amp;#39;{x: number}&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="constructor-privado"&gt;Constructor privado&lt;/h2&gt;
&lt;p&gt;Un constructor &lt;code&gt;private&lt;/code&gt; impide instanciar la clase desde fuera, lo que permite controlar su creación. Es la base del patrón &lt;em&gt;singleton&lt;/em&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#c678dd"&gt;static&lt;/span&gt; &lt;span style="color:#e06c75"&gt;instance&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Apocalipsis&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#c678dd"&gt;constructor&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;static&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getInstance&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;instance&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;instance&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Soy Apocalipsis... el único&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;instance&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;apocalipsis&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Apocalipsis&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getInstance&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="patrones-de-diseño-habilitados"&gt;Patrones de diseño habilitados&lt;/h2&gt;
&lt;h3 id="factory-pattern"&gt;Factory Pattern&lt;/h3&gt;
&lt;p&gt;Centraliza la creación de objetos detrás de una función que decide la clase concreta:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;purpose&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;BalletFlat&lt;/span&gt; &lt;span style="color:#c678dd"&gt;implements&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;purpose&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;dancing&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Boot&lt;/span&gt; &lt;span style="color:#c678dd"&gt;implements&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;purpose&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;woodcutting&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Sneaker&lt;/span&gt; &lt;span style="color:#c678dd"&gt;implements&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;purpose&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;walking&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;create&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;type&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;balletFlat&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;boot&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;sneaker&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Shoe&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;switch&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;type&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;case&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;balletFlat&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;BalletFlat&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;case&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;boot&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Boot&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;case&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;sneaker&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Sneaker&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="builder-pattern"&gt;Builder Pattern&lt;/h3&gt;
&lt;p&gt;Construye un objeto paso a paso mediante métodos que retornan &lt;code&gt;this&lt;/code&gt;, habilitando una API fluida:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;RequestBuilder&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;object&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;method&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;get&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;post&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;private&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;setMethod&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;method&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;get&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;post&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;method&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;method&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;setData&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;object&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;data&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;setURL&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;send() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;RequestBuilder&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;setURL&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;/api&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;setMethod&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;post&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;setData&lt;/span&gt;({}).&lt;span style="color:#e06c75"&gt;send&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Las clases de TypeScript ofrecen un modelo de orientación a objetos completo: herencia, modificadores de acceso, clases abstractas para polimorfismo, accessors, miembros estáticos y un tipado estructural con la salvedad de los miembros privados. Estas piezas son el fundamento de patrones de diseño como Factory, Builder y Singleton.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo abordaremos los &lt;strong&gt;genéricos&lt;/strong&gt;, la herramienta para escribir código reutilizable sin sacrificar la seguridad de tipos.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Interfaces y contratos de tipos</title><link>https://blog.dacadev.com/typescript/interfaces/</link><pubDate>Thu, 18 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/interfaces/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Domina las interfaces en TypeScript: contratos extensibles, herencia con extends, implementación en clases, diferencias con type y declaration merging.</description><media:content url="https://blog.dacadev.com/images/typescript/interfaces/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#bases-definir-y-extender-interfaces"&gt;Bases: definir y extender interfaces&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#estructuras-complejas-interfaces-anidadas"&gt;Estructuras complejas: interfaces anidadas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#métodos-en-la-interfaz"&gt;Métodos en la interfaz&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#implementar-interfaces-en-clases"&gt;Implementar interfaces en clases&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#interfaces-para-tipar-funciones"&gt;Interfaces para tipar funciones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#interfaces-frente-a-alias-de-tipo"&gt;Interfaces frente a alias de tipo&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#1-composición"&gt;1. Composición&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#2-restricción-al-extender"&gt;2. Restricción al extender&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#3-declaration-merging"&gt;3. Declaration merging&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#implementación-con-readonly-y-múltiples-contratos"&gt;Implementación con readonly y múltiples contratos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Quinto artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Estudiaremos las interfaces como contratos extensibles, su herencia con &lt;code&gt;extends&lt;/code&gt;, su implementación en clases con &lt;code&gt;implements&lt;/code&gt;, y sus diferencias frente a los alias de tipo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Una &lt;strong&gt;interface&lt;/strong&gt; en TypeScript define la forma que deben cumplir los objetos. A primera vista se parece a un alias de tipo, pero su rasgo distintivo es la &lt;strong&gt;extensibilidad&lt;/strong&gt;: las interfaces están diseñadas para componerse, heredarse y servir como base de contratos más complejos. Analicemos cuándo y cómo usarlas.&lt;/p&gt;
&lt;h2 id="bases-definir-y-extender-interfaces"&gt;Bases: definir y extender interfaces&lt;/h2&gt;
&lt;p&gt;Una interface declara la estructura de un objeto. Con &lt;code&gt;extends&lt;/code&gt;, una interface puede heredar de otra y ampliar su contrato:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Avenger&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;marvel&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;flash&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Barry Allen&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;24&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;super velocidad&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;viajar en el tiempo&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Avenger&lt;/code&gt; hereda todos los miembros de &lt;code&gt;Hero&lt;/code&gt; y añade &lt;code&gt;marvel&lt;/code&gt;. Esta composición es la base del diseño orientado a contratos.&lt;/p&gt;
&lt;h2 id="estructuras-complejas-interfaces-anidadas"&gt;Estructuras complejas: interfaces anidadas&lt;/h2&gt;
&lt;p&gt;Las interfaces pueden referenciarse entre sí para modelar estructuras de datos compuestas:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Client&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;address?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Address&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Address&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;zip&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;city&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;client&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Client&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;address&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;125&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;zip&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;KYD 234&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;city&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Chía&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;client2&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Client&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Melissa&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;30&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Client&lt;/code&gt; referencia a &lt;code&gt;Address&lt;/code&gt; como un campo opcional, lo que permite componer entidades de dominio sin acoplarlas en una sola definición monolítica.&lt;/p&gt;
&lt;h2 id="métodos-en-la-interfaz"&gt;Métodos en la interfaz&lt;/h2&gt;
&lt;p&gt;Al igual que los alias de tipo, las interfaces pueden declarar métodos como parte del contrato:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Client&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;address?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Address&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getFullAddress&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Declarar métodos en una interface es válido, pero implica que el objeto que la cumpla debe implementarlos. En la práctica, cuando un contrato requiere comportamiento, lo más limpio es implementarlo mediante una clase.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="implementar-interfaces-en-clases"&gt;Implementar interfaces en clases&lt;/h2&gt;
&lt;p&gt;Una clase adopta uno o varios contratos con la palabra clave &lt;code&gt;implements&lt;/code&gt;. Esto garantiza, en compilación, que la clase provee todo lo que el contrato exige:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mutantPower&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Human&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Mutant&lt;/span&gt; &lt;span style="color:#c678dd"&gt;implements&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Xmen&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Human&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;public&lt;/span&gt; &lt;span style="color:#e06c75"&gt;realName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mutantPower&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Hola mundo&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Mutant&lt;/code&gt; implementa simultáneamente &lt;code&gt;Xmen&lt;/code&gt; y &lt;code&gt;Human&lt;/code&gt;. Si omitiera cualquier miembro requerido, el compilador lo rechazaría.&lt;/p&gt;
&lt;h2 id="interfaces-para-tipar-funciones"&gt;Interfaces para tipar funciones&lt;/h2&gt;
&lt;p&gt;Aunque es poco frecuente, una interface puede describir la firma de una función antes de asignarle una implementación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;AddTwoNumbers&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;addNumbers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;AddTwoNumbers&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;addNumbers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="interfaces-frente-a-alias-de-tipo"&gt;Interfaces frente a alias de tipo&lt;/h2&gt;
&lt;p&gt;Esta es la decisión de diseño más común. Las tres diferencias clave:&lt;/p&gt;
&lt;h3 id="1-composición"&gt;1. Composición&lt;/h3&gt;
&lt;p&gt;Los alias de tipo componen mediante operaciones de conjuntos (&lt;code&gt;|&lt;/code&gt;, &lt;code&gt;&amp;amp;&lt;/code&gt;); las interfaces componen mediante &lt;code&gt;extends&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Food&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;calories&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;tasty&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Sushi&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Food&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;amp;&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;salty&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;FoodI&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;calories&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;tasty&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SushiI&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;FoodI&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;salty&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="2-restricción-al-extender"&gt;2. Restricción al extender&lt;/h3&gt;
&lt;p&gt;Al extender una interface, no puedes &lt;strong&gt;cambiar&lt;/strong&gt; el tipo de un miembro heredado, solo añadir o restringir de forma compatible. Una incompatibilidad genera error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;good&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;bad&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;B&lt;/span&gt; &lt;span style="color:#c678dd"&gt;extends&lt;/span&gt; &lt;span style="color:#e06c75"&gt;A&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;good&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;bad&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;x&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2430: &amp;#39;B&amp;#39; extiende incorrectamente &amp;#39;A&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-declaration-merging"&gt;3. Declaration merging&lt;/h3&gt;
&lt;p&gt;Varias interfaces con el mismo nombre en el mismo ámbito &lt;strong&gt;se fusionan automáticamente&lt;/strong&gt;; varios alias de tipo con el mismo nombre producen un error de compilación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; } &lt;span style="color:#7f848e"&gt;// se fusiona
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;User&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Ashley&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;30&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; } &lt;span style="color:#7f848e"&gt;// Error TS2300: identificador duplicado
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; } &lt;span style="color:#7f848e"&gt;// Error TS2300
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El &lt;em&gt;declaration merging&lt;/em&gt; respeta los tipos existentes: no puedes redefinir un miembro ya declarado con otro tipo.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 Q{¿Necesitas extensibilidad,&lt;br/&gt;implements o merging?}
 Q -- Sí --&gt; I[Usa interface]
 Q -- "No (uniones, tuplas, mapeos)" --&gt; T[Usa type]
&lt;/pre&gt;

&lt;h2 id="implementación-con-readonly-y-múltiples-contratos"&gt;Implementación con readonly y múltiples contratos&lt;/h2&gt;
&lt;p&gt;Las interfaces admiten propiedades &lt;code&gt;readonly&lt;/code&gt; y permiten que una clase cumpla varios contratos a la vez:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Animal&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;readonly&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;eat&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;food&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;hours&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Feline&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;meow&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;void&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Cat&lt;/span&gt; &lt;span style="color:#c678dd"&gt;implements&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Animal&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Feline&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Whiskers&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;eat&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;food&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) { &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Ate some&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;food&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;hours&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) { &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Slept for&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;hours&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;hours&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;meow() {&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Meow&amp;#39;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Las interfaces son el mecanismo de TypeScript para definir contratos extensibles y verificables. Elige una interface cuando necesites herencia con &lt;code&gt;extends&lt;/code&gt;, implementación en clases con &lt;code&gt;implements&lt;/code&gt; o &lt;em&gt;declaration merging&lt;/em&gt;; reserva los alias de tipo para uniones, intersecciones, tuplas y tipos mapeados.&lt;/p&gt;
&lt;p&gt;En el próximo artículo profundizaremos en las &lt;strong&gt;clases&lt;/strong&gt;, la herencia, los modificadores de acceso y los patrones de diseño que habilitan.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Funciones, parámetros y generadores</title><link>https://blog.dacadev.com/typescript/funciones/</link><pubDate>Wed, 17 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/funciones/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a tipar funciones en TypeScript: tipos de retorno, parámetros opcionales y por defecto, operador resto, call signatures, generadores e iteradores.</description><media:content url="https://blog.dacadev.com/images/typescript/functions/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#declaración-y-tipado-de-funciones"&gt;Declaración y tipado de funciones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#parámetros-opcionales-y-por-defecto"&gt;Parámetros opcionales y por defecto&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#operador-resto-funciones-variádicas"&gt;Operador resto: funciones variádicas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#call-apply-y-bind"&gt;call, apply y bind&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#generadores"&gt;Generadores&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#iteradores"&gt;Iteradores&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#call-signatures"&gt;Call signatures&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Cuarto artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Cubriremos el tipado de funciones: parámetros, tipos de retorno, parámetros opcionales y por defecto, el operador resto, &lt;em&gt;call signatures&lt;/em&gt;, generadores e iteradores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Las funciones son el núcleo de cualquier base de código, y es justo donde el tipado aporta más valor: una firma bien tipada documenta el contrato de entrada y salida, y convierte cualquier llamada inválida en un error de compilación. Analicemos cómo TypeScript modela las &lt;strong&gt;funciones&lt;/strong&gt; en toda su variedad.&lt;/p&gt;
&lt;h2 id="declaración-y-tipado-de-funciones"&gt;Declaración y tipado de funciones&lt;/h2&gt;
&lt;p&gt;Una función tipada declara el tipo de cada parámetro y, opcionalmente, el tipo de retorno:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TypeScript admite todas las formas de definir funciones de JavaScript, y a todas les aplica el mismo sistema de tipos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Named function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;greet&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello &amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Function expression
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;greet2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello &amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Arrow function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;greet3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello &amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Shorthand arrow function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;greet4&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello &amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El tipado de los parámetros intercepta llamadas inválidas en el sitio exacto del error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// Error TS2554: se esperaban 2 argumentos, se recibió 1.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// Error TS2345: &amp;#39;string&amp;#39; no es asignable a &amp;#39;number&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="parámetros-opcionales-y-por-defecto"&gt;Parámetros opcionales y por defecto&lt;/h2&gt;
&lt;p&gt;Un parámetro opcional se marca con &lt;code&gt;?&lt;/code&gt; y debe gestionarse dentro del cuerpo, ya que puede llegar como &lt;code&gt;undefined&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;userId?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Date&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;toLocaleTimeString&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;userId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;||&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Not signed in&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Page loaded&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;User signed in&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;da763be&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un parámetro con valor por defecto se vuelve opcional automáticamente, y TypeScript infiere su tipo a partir del valor asignado:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;userId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Not signed in&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Date&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;toISOString&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;userId&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los parámetros opcionales deben ubicarse &lt;strong&gt;después&lt;/strong&gt; de todos los obligatorios, y no pueden combinarse con el operador resto.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;También puedes apoyarte en un &lt;code&gt;type&lt;/code&gt; para estructurar parámetros de configuración:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Context&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;appId?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;userId?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;context&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Context&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {}) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Date&lt;/span&gt;().&lt;span style="color:#e06c75"&gt;toISOString&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;message&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;context&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;userId&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="operador-resto-funciones-variádicas"&gt;Operador resto: funciones variádicas&lt;/h2&gt;
&lt;p&gt;El operador resto captura un número dinámico de argumentos en un arreglo tipado, lo que produce firmas más legibles que recibir un arreglo explícito:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Recibe un arreglo
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sum&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;[])&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sum&lt;/span&gt;([&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]) &lt;span style="color:#7f848e"&gt;// 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Variádica con operador resto
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sumVariadicSafe&lt;/span&gt;(...&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;[])&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;sumVariadicSafe&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// 6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="call-apply-y-bind"&gt;call, apply y bind&lt;/h2&gt;
&lt;p&gt;TypeScript respeta los mecanismos clásicos de invocación de JavaScript, aplicando la verificación de tipos a sus argumentos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;apply&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;, [&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;]) &lt;span style="color:#7f848e"&gt;// 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;call&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;bind&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;)() &lt;span style="color:#7f848e"&gt;// 30
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="generadores"&gt;Generadores&lt;/h2&gt;
&lt;p&gt;Los generadores producen valores bajo demanda. Se declaran con un asterisco tras &lt;code&gt;function&lt;/code&gt; y emiten valores con &lt;code&gt;yield&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#e06c75"&gt;createFibonacciGenerator() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;while&lt;/span&gt; (&lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;yield&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ;[&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;b&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fib&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;createFibonacciGenerator&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;// IterableIterator&amp;lt;number&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fib&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;// { value: 0, done: false }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fib&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;// { value: 1, done: false }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fib&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;// { value: 1, done: false }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fib&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;// { value: 2, done: false }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El método &lt;code&gt;next()&lt;/code&gt; extrae el siguiente valor de la secuencia. TypeScript infiere el tipo &lt;code&gt;IterableIterator&amp;lt;number&amp;gt;&lt;/code&gt; a partir de lo que produce &lt;code&gt;yield&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="iteradores"&gt;Iteradores&lt;/h2&gt;
&lt;p&gt;Un iterador se define implementando el método &lt;code&gt;[Symbol.iterator]&lt;/code&gt;. TypeScript es capaz de reconocer la estructura y tiparla correctamente:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;[&lt;span style="color:#e06c75"&gt;Symbol&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;iterator&lt;/span&gt;]() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;++&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;yield&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="call-signatures"&gt;Call signatures&lt;/h2&gt;
&lt;p&gt;Una &lt;em&gt;call signature&lt;/em&gt; describe el tipo de una función de forma independiente a su implementación. Para la siguiente función:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sum&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;su firma de llamada se expresa así:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El tipo genérico &lt;code&gt;Function&lt;/code&gt; es un comodín que no aporta información sobre la firma concreta; las &lt;em&gt;call signatures&lt;/em&gt; permiten tipar funciones con precisión. Además, cuando una función puede retornar varios tipos, cada uno debe tratarse para satisfacer al typechecker:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;area&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;radius&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;radius&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Math&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;PI&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#e06c75"&gt;radius&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;**&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;area&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;!==&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;result:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// dentro del guard, a es number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;El tipado de funciones convierte cada firma en un contrato verificable: parámetros opcionales y por defecto modelan flexibilidad controlada, el operador resto expresa funciones variádicas con claridad, las &lt;em&gt;call signatures&lt;/em&gt; tipan funciones como ciudadanos de primera clase, y los generadores e iteradores se integran sin fricción en el sistema de tipos.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo abordaremos las &lt;strong&gt;interfaces&lt;/strong&gt;, el mecanismo de TypeScript para definir contratos extensibles.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Objetos y tipos personalizados</title><link>https://blog.dacadev.com/typescript/objetos-y-tipos-personalizados/</link><pubDate>Tue, 16 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/objetos-y-tipos-personalizados/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a tipar objetos literales en TypeScript, definir tipos personalizados con type, usar campos opcionales y métodos, y permitir múltiples tipos con uniones.</description><media:content url="https://blog.dacadev.com/images/typescript/objects-custom-types/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#objetos-literales-y-la-inferencia-estructural"&gt;Objetos literales y la inferencia estructural&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipar-objetos-de-forma-inline"&gt;Tipar objetos de forma inline&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipos-personalizados-con-type"&gt;Tipos personalizados con type&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#permitir-múltiples-tipos-con-uniones"&gt;Permitir múltiples tipos con uniones&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Tercer artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Diseñaremos la forma de nuestros objetos con tipos personalizados, definiremos campos opcionales y métodos, y permitiremos que una variable acepte múltiples tipos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Modelar correctamente la estructura de los objetos es donde TypeScript empieza a pagar dividendos en proyectos reales. Un &lt;strong&gt;tipo personalizado&lt;/strong&gt; bien diseñado centraliza la definición de una entidad, propaga su forma por todo el código y convierte cualquier desviación en un error de compilación. Analicemos cómo pasar de objetos literales sueltos a un modelo de tipos mantenible.&lt;/p&gt;
&lt;h2 id="objetos-literales-y-la-inferencia-estructural"&gt;Objetos literales y la inferencia estructural&lt;/h2&gt;
&lt;p&gt;Los objetos literales funcionan igual que en JavaScript, pero TypeScript infiere automáticamente su estructura. Esa inferencia es justamente lo que impide reasignar un objeto con una forma distinta:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;flash&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Barry Allen&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;24&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;super velocidad&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;viajar en el tiempo&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;flash&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name2&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Otro nombre&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Error: el literal solo puede especificar propiedades conocidas;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// &amp;#39;name2&amp;#39; no existe en el tipo inferido y faltan &amp;#39;name&amp;#39;, &amp;#39;age&amp;#39;, &amp;#39;powers&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TypeScript bloquea la reasignación porque el nuevo literal no respeta la forma deducida de &lt;code&gt;flash&lt;/code&gt;. Este comportamiento evita introducir campos accidentales o incompletos.&lt;/p&gt;
&lt;h2 id="tipar-objetos-de-forma-inline"&gt;Tipar objetos de forma inline&lt;/h2&gt;
&lt;p&gt;Podemos declarar explícitamente la forma del objeto usando la misma sintaxis de anotación que venimos aplicando, incluyendo campos opcionales con &lt;code&gt;?&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;flash&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;[] } &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Barry Allen&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;24&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;super velocidad&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;viajar en el tiempo&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;flash&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Clark Kent&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;volar&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;rayo láser&amp;#39;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// &amp;#39;age&amp;#39; es opcional, puede omitirse
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La posición de un campo opcional dentro de la anotación es irrelevante. &lt;code&gt;age?&lt;/code&gt; puede ir en medio de la definición sin afectar la validez de los objetos que lo omitan.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El problema de este enfoque &lt;em&gt;inline&lt;/em&gt; es la duplicación: si dos variables deben compartir la misma forma, hay que repetir la anotación completa en cada una y mantenerlas sincronizadas manualmente. Esto no escala.&lt;/p&gt;
&lt;h2 id="tipos-personalizados-con-type"&gt;Tipos personalizados con type&lt;/h2&gt;
&lt;p&gt;La solución es definir la estructura una sola vez con la palabra clave &lt;code&gt;type&lt;/code&gt; y reutilizarla en todo el código. Esto centraliza el modelo en un único punto de verdad:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;flash&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Barry Allen&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;24&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;super velocidad&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;viajar en el tiempo&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;superman&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Clark Kent&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;30&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;volar&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;rayo láser&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getName() {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El tipo &lt;code&gt;Hero&lt;/code&gt; declara &lt;code&gt;name&lt;/code&gt; y &lt;code&gt;powers&lt;/code&gt; como obligatorios, &lt;code&gt;age&lt;/code&gt; como opcional y &lt;code&gt;getName&lt;/code&gt; como un &lt;strong&gt;método opcional&lt;/strong&gt; cuya firma es &lt;code&gt;() =&amp;gt; string&lt;/code&gt;. Cualquier objeto anotado con &lt;code&gt;Hero&lt;/code&gt; debe respetar este contrato, y un solo cambio en la definición se propaga a todas las variables que lo usan.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 T[type Hero] --&gt; A[flash: Hero]
 T --&gt; B[superman: Hero]
 T --&gt; C[...otros héroes]
 note["Un cambio en Hero&lt;br/&gt;se propaga a todos"] -.-&gt; T
&lt;/pre&gt;





 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Define un &lt;code&gt;type&lt;/code&gt; para toda entidad que aparezca más de una vez. La regla práctica: si copiarías la anotación inline por segunda vez, conviértela en un tipo personalizado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="permitir-múltiples-tipos-con-uniones"&gt;Permitir múltiples tipos con uniones&lt;/h2&gt;
&lt;p&gt;Una variable puede aceptar más de un tipo mediante el operador de unión &lt;code&gt;|&lt;/code&gt;. Esto resulta útil para valores que legítimamente cambian de forma según el contexto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;[];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;myCustomVariable&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Hero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;¡Hola mundo!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;myCustomVariable&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;42&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// válido: number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;myCustomVariable&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#7f848e"&gt;// válido: Hero
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Diana&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;powers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;fuerza sobrehumana&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;myCustomVariable&lt;/code&gt; puede contener un &lt;code&gt;Hero&lt;/code&gt;, un &lt;code&gt;string&lt;/code&gt; o un &lt;code&gt;number&lt;/code&gt;. El typechecker permitirá únicamente operaciones válidas para todos los miembros de la unión hasta que acotes el tipo con un &lt;em&gt;type guard&lt;/em&gt; (por ejemplo, &lt;code&gt;typeof&lt;/code&gt; o una comprobación de propiedad).&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Pasar de objetos literales inline a tipos personalizados con &lt;code&gt;type&lt;/code&gt; es el salto que transforma TypeScript de una simple validación a una herramienta de diseño. Un tipo centraliza la forma de una entidad, los campos opcionales modelan la realidad de los datos incompletos, los métodos definen comportamiento esperado y las uniones aportan flexibilidad controlada.&lt;/p&gt;
&lt;p&gt;En el próximo artículo de la serie abordaremos las &lt;strong&gt;funciones&lt;/strong&gt;: anotación de parámetros, tipos de retorno, parámetros opcionales y sobrecargas.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Tipos básicos y el sistema de tipos</title><link>https://blog.dacadev.com/typescript/tipos-basicos/</link><pubDate>Mon, 15 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/tipos-basicos/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Domina los tipos básicos de TypeScript: any, unknown, boolean, number, bigint, string, symbol, objetos, alias, uniones, intersecciones, arreglos y tuplas.</description><media:content url="https://blog.dacadev.com/images/typescript/basic-types/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-importan-los-tipos-un-ejemplo-concreto"&gt;Por qué importan los tipos: un ejemplo concreto&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#any-la-puerta-de-escape-del-sistema-de-tipos"&gt;any: la puerta de escape del sistema de tipos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#unknown-la-alternativa-segura-a-any"&gt;unknown: la alternativa segura a any&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#boolean"&gt;boolean&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#number-y-bigint"&gt;number y bigint&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#string"&gt;string&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#symbol"&gt;symbol&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#objetos"&gt;Objetos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#alias-de-tipo"&gt;Alias de tipo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipos-unión-e-intersección"&gt;Tipos unión e intersección&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#arreglos"&gt;Arreglos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tuplas"&gt;Tuplas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Segundo artículo de la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Recorreremos el alfabeto de tipos del lenguaje: desde &lt;code&gt;any&lt;/code&gt; y &lt;code&gt;unknown&lt;/code&gt; hasta uniones, intersecciones, tuplas y alias de tipo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Cuando el typechecker sabe que un valor es de tipo &lt;code&gt;T&lt;/code&gt;, no solo conoce su naturaleza: también sabe &lt;strong&gt;exactamente qué operaciones son válidas&lt;/strong&gt; sobre ese valor y cuáles no. Ese es el propósito del sistema de tipos. Comprender el catálogo de &lt;strong&gt;tipos básicos en TypeScript&lt;/strong&gt; es la base sobre la que se construye todo lo demás, así que dediquémosle la atención que merece.&lt;/p&gt;
&lt;h2 id="por-qué-importan-los-tipos-un-ejemplo-concreto"&gt;Por qué importan los tipos: un ejemplo concreto&lt;/h2&gt;
&lt;p&gt;Los tipos transmiten intención de forma explícita y verificable. Comparemos la misma función en JavaScript y en TypeScript:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// JavaScript
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// NaN — falla en silencio
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// TypeScript
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; &lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;n&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#e06c75"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// 4
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;squareOf&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// Error TS2345: el argumento de tipo &amp;#39;string&amp;#39; no es
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// asignable al parámetro de tipo &amp;#39;number&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En JavaScript, &lt;code&gt;squareOf('z')&lt;/code&gt; devuelve &lt;code&gt;NaN&lt;/code&gt; sin protestar y el error se propaga aguas abajo. En TypeScript el compilador lo intercepta en el sitio exacto donde se cometió.&lt;/p&gt;
&lt;h2 id="any-la-puerta-de-escape-del-sistema-de-tipos"&gt;any: la puerta de escape del sistema de tipos&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;any&lt;/code&gt; indica que una variable puede contener cualquier tipo de dato. Desactiva por completo la verificación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;avenger&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;any&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;123&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;avenger&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Dr. Strange&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;avenger&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;charAt&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;0&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;avenger&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;15.23425&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;((&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;&lt;span style="color:#e06c75"&gt;avenger&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;toFixed&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cuando usas &lt;code&gt;any&lt;/code&gt;, el typechecker deja de ayudarte. Puedes reorientarlo mediante un &lt;em&gt;cast&lt;/em&gt; —indicar manualmente qué tipo debe asumir en un punto dado— con la sintaxis &lt;code&gt;(variable as Tipo)&lt;/code&gt; o &lt;code&gt;&amp;lt;Tipo&amp;gt;variable&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Evita &lt;code&gt;any&lt;/code&gt; salvo en migraciones puntuales o fronteras con código sin tipado. Cada &lt;code&gt;any&lt;/code&gt; es un agujero por el que se filtran errores que el compilador debería haber detenido.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="unknown-la-alternativa-segura-a-any"&gt;unknown: la alternativa segura a any&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;unknown&lt;/code&gt; es el primo responsable de &lt;code&gt;any&lt;/code&gt;. Acepta cualquier valor, pero &lt;strong&gt;TypeScript prohíbe operar sobre él&lt;/strong&gt; hasta que acotes su tipo mediante una comprobación. Esto añade una capa de seguridad: sí admite operaciones de comparación e identidad (&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;===&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, el operador ternario &lt;code&gt;?&lt;/code&gt;) y negación con &lt;code&gt;!&lt;/code&gt;, pero no el acceso a propiedades arbitrarias.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dato&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;unknown&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obtenerValor&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// dato.toFixed(2) // Error: &amp;#39;dato&amp;#39; es de tipo &amp;#39;unknown&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#c678dd"&gt;typeof&lt;/span&gt; &lt;span style="color:#e06c75"&gt;dato&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;number&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;dato&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;toFixed&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// OK: dentro del guard, dato es number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Usa &lt;code&gt;unknown&lt;/code&gt; siempre que recibas datos externos (respuestas de API, entrada del usuario) en lugar de &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="boolean"&gt;boolean&lt;/h2&gt;
&lt;p&gt;Acepta las operaciones &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;===&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, el ternario &lt;code&gt;?&lt;/code&gt; y la negación &lt;code&gt;!&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// boolean
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// true (tipo literal)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;d&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// boolean
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;e&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;f&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;false&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2322: &amp;#39;false&amp;#39; no es asignable a &amp;#39;true&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;El tipo &lt;code&gt;true&lt;/code&gt; (literal) es más restrictivo que &lt;code&gt;boolean&lt;/code&gt;: además de exigir un booleano, exige que su valor sea exactamente &lt;code&gt;true&lt;/code&gt;. Los &lt;strong&gt;tipos literales&lt;/strong&gt; son una herramienta poderosa para modelar estados precisos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="number-y-bigint"&gt;number y bigint&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;number&lt;/code&gt; cubre enteros, flotantes, &lt;code&gt;Infinity&lt;/code&gt;, &lt;code&gt;NaN&lt;/code&gt; y valores positivos y negativos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1234&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;5678&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// 5678 (literal)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;e&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;100&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;f&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;26.218&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;26.218&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// 26.218 (literal)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;g&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;26.218&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2322
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un &lt;code&gt;number&lt;/code&gt; representa con precisión hasta 2^53. Para enteros mayores existe &lt;code&gt;bigint&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1234&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// bigint
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;5678&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// 5678n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;e&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;88.5&lt;/span&gt;&lt;span style="color:#e06c75"&gt;n&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS1353: un literal bigint debe ser entero.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;h&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;bigint&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;100&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2322: &amp;#39;100&amp;#39; no es asignable a &amp;#39;bigint&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="string"&gt;string&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;!&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// &amp;#39;!&amp;#39; (literal)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;e&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;zoom&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;f&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;john&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;john&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// &amp;#39;john&amp;#39; (literal)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;g&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;john&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;zoe&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2322
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="symbol"&gt;symbol&lt;/h2&gt;
&lt;p&gt;Un &lt;code&gt;symbol&lt;/code&gt; representa un identificador único. Se crea con &lt;code&gt;Symbol()&lt;/code&gt; y admite una descripción opcional útil para depurar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;); &lt;span style="color:#7f848e"&gt;// symbol con descripción &amp;#34;id&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La garantía clave: &lt;strong&gt;dos símbolos nunca son iguales&lt;/strong&gt;, aunque compartan descripción. La descripción es solo una etiqueta sin efecto sobre la identidad.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Symbol&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;id1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id2&lt;/span&gt;); &lt;span style="color:#7f848e"&gt;// false
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;d&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;id1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;x&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2469: el operador &amp;#39;+&amp;#39; no aplica a &amp;#39;symbol&amp;#39;.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="objetos"&gt;Objetos&lt;/h2&gt;
&lt;p&gt;Hay dos formas de tipar objetos. La primera usa la palabra clave &lt;code&gt;object&lt;/code&gt;, que solo garantiza que el valor no es &lt;code&gt;null&lt;/code&gt; pero &lt;strong&gt;no expone sus propiedades&lt;/strong&gt;, porque TypeScript no sabe qué objeto es:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;object&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;x&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// a.b // Error: la propiedad &amp;#39;b&amp;#39; no existe en el tipo &amp;#39;object&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La segunda —y recomendada— describe la forma exacta del objeto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;firstName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;lastName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;firstName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;john&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;lastName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;barrowman&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Las definiciones de objeto admiten campos opcionales (&lt;code&gt;?&lt;/code&gt;), índices dinámicos y propiedades de solo lectura:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// obligatorio, number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;c?&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// opcional, string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;]&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#c678dd"&gt;boolean&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// cualquier clave numérica → boolean
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;readonly&lt;/span&gt; &lt;span style="color:#e06c75"&gt;firstName&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;firstName&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;abby&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;firstName&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;abbey&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// Error TS2540: propiedad de solo lectura.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Evita tipar con el objeto vacío &lt;code&gt;{}&lt;/code&gt;. Acepta cualquier valor distinto de &lt;code&gt;null&lt;/code&gt; o &lt;code&gt;undefined&lt;/code&gt; (incluso números o arreglos), lo que vacía de sentido la anotación.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="alias-de-tipo"&gt;Alias de tipo&lt;/h2&gt;
&lt;p&gt;Los alias asignan un nombre semántico a un tipo, mejorando la legibilidad sin alterar la verificación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Age&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Person&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Age&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;driver&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Person&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;James May&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;age&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;55&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Como &lt;code&gt;Age&lt;/code&gt; es solo un alias de &lt;code&gt;number&lt;/code&gt;, sigue siendo compatible con cualquier &lt;code&gt;number&lt;/code&gt;. Ten presente que un alias &lt;strong&gt;solo puede declararse una vez&lt;/strong&gt; por ámbito; aplica las mismas reglas de &lt;em&gt;shadowing&lt;/em&gt; que &lt;code&gt;let&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt; y &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="tipos-unión-e-intersección"&gt;Tipos unión e intersección&lt;/h2&gt;
&lt;p&gt;Recurriendo a la teoría de conjuntos: la &lt;strong&gt;unión&lt;/strong&gt; (&lt;code&gt;|&lt;/code&gt;) admite uno u otro tipo —o ambos—, mientras que la &lt;strong&gt;intersección&lt;/strong&gt; (&lt;code&gt;&amp;amp;&lt;/code&gt;) exige cumplir simultáneamente todas las formas combinadas.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 subgraph Union["A | B"]
 U[Cualquier valor que sea A, B o ambos]
 end
 subgraph Inter["A &amp; B"]
 I[Solo valores que cumplen A y B a la vez]
 end
&lt;/pre&gt;

&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Cat&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;purrs&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Dog&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;barks&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;wags&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CatOrDogOrBoth&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Cat&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Dog&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// unión
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CatAndDog&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Cat&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Dog&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// intersección
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un valor &lt;code&gt;Cat | Dog&lt;/code&gt; puede ser un gato, un perro o un objeto que cumpla ambas formas. Un valor &lt;code&gt;Cat &amp;amp; Dog&lt;/code&gt;, en cambio, está obligado a tener &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;purrs&lt;/code&gt;, &lt;code&gt;barks&lt;/code&gt; y &lt;code&gt;wags&lt;/code&gt; al mismo tiempo.&lt;/p&gt;
&lt;h2 id="arreglos"&gt;Arreglos&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// number[]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;d&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// (string | number)[]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;h&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; []
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;h&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;push&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;h&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;push&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;// Error TS2345
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Un arreglo declarado vacío sin anotación arranca como &lt;code&gt;any[]&lt;/code&gt; y va ampliando su tipo según lo que insertes —otra razón para anotar explícitamente las colecciones en las fronteras del sistema.&lt;/p&gt;
&lt;h2 id="tuplas"&gt;Tuplas&lt;/h2&gt;
&lt;p&gt;Las tuplas son un subconjunto de los arreglos con &lt;strong&gt;longitud fija&lt;/strong&gt; y tipos posicionales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// [nombre, apellido, año de nacimiento]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;malcolm&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;gladwell&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1963&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;queen&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;elizabeth&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;ii&amp;#39;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1926&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// Error TS2322: posición/longitud inválida
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;También admiten posiciones opcionales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Tarifas de tren que a veces varían según la dirección
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;trainFares&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; [&lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;][] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#d19a66"&gt;3.75&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#d19a66"&gt;8.25&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;7.70&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#d19a66"&gt;10.50&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;El sistema de tipos de TypeScript va mucho más allá de etiquetar variables: distingue entre &lt;code&gt;any&lt;/code&gt; (inseguro) y &lt;code&gt;unknown&lt;/code&gt; (seguro), modela estados exactos con tipos literales, compone formas mediante uniones e intersecciones y garantiza estructuras rígidas con tuplas. Dominar este catálogo es el prerrequisito para los temas avanzados de la serie.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo aplicaremos estos fundamentos a los &lt;strong&gt;objetos y tipos personalizados&lt;/strong&gt;, donde los alias de tipo se vuelven el centro del diseño.&lt;/p&gt;</content:encoded></item><item><title>TypeScript: Introducción y configuración del entorno</title><link>https://blog.dacadev.com/typescript/introduccion-a-typescript/</link><pubDate>Sun, 14 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/introduccion-a-typescript/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende qué es TypeScript, cómo funciona su compilador, cómo instalarlo y configurar tsconfig.json para iniciar un proyecto profesional con tipado estático.</description><media:content url="https://blog.dacadev.com/images/typescript/introduction/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#cómo-se-ejecuta-el-código-ast-bytecode-y-runtime"&gt;¿Cómo se ejecuta el código? AST, bytecode y runtime&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#el-sistema-de-tipos"&gt;El sistema de tipos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#instalación-de-typescript"&gt;Instalación de TypeScript&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tsconfigjson-el-corazón-de-la-configuración"&gt;tsconfig.json: el corazón de la configuración&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#el-archivo-de-entrada-indexts"&gt;El archivo de entrada: index.ts&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#hola-mundo-y-la-verificación-de-tipos-en-acción"&gt;Hola mundo y la verificación de tipos en acción&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#watch-mode-compilación-continua"&gt;Watch mode: compilación continua&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo abre la serie sobre &lt;strong&gt;TypeScript&lt;/strong&gt;. Aquí analizaremos qué problema resuelve el tipado estático, cómo opera el compilador &lt;code&gt;tsc&lt;/code&gt; y cómo dejar listo un proyecto profesional con &lt;code&gt;tsconfig.json&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;JavaScript resuelve los tipos en tiempo de ejecución. Esto significa que un error tan trivial como pasar un &lt;code&gt;string&lt;/code&gt; donde se esperaba un &lt;code&gt;number&lt;/code&gt; solo se manifiesta cuando el código ya está corriendo, frecuentemente en producción y bajo la forma de un &lt;code&gt;NaN&lt;/code&gt; silencioso o una excepción difícil de rastrear. &lt;strong&gt;TypeScript&lt;/strong&gt; ataca este problema en la raíz: agrega un sistema de tipos estático sobre JavaScript que traslada la detección de errores desde el runtime hacia el tiempo de compilación.&lt;/p&gt;
&lt;h2 id="cómo-se-ejecuta-el-código-ast-bytecode-y-runtime"&gt;¿Cómo se ejecuta el código? AST, bytecode y runtime&lt;/h2&gt;
&lt;p&gt;Para entender qué aporta TypeScript conviene recordar el ciclo de vida de un programa en un motor de JavaScript:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;El programa se parsea hacia un &lt;strong&gt;AST&lt;/strong&gt; (Abstract Syntax Tree).&lt;/li&gt;
&lt;li&gt;El AST se compila a &lt;strong&gt;bytecode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;El bytecode es evaluado por el &lt;strong&gt;runtime&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;TypeScript se inserta antes de este flujo. El compilador &lt;code&gt;tsc&lt;/code&gt; toma tu código &lt;code&gt;.ts&lt;/code&gt;, construye su propio AST, lo somete al &lt;strong&gt;typechecker&lt;/strong&gt; y, si todo es válido, emite JavaScript estándar que cualquier motor puede ejecutar.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[Código TypeScript] --&gt; B[AST de TypeScript]
 B --&gt; C{Typechecker}
 C -- válido --&gt; D[JavaScript emitido]
 C -- error --&gt; E[Error en compilación]
 D --&gt; F[AST de JavaScript]
 F --&gt; G[Bytecode]
 G --&gt; H[Runtime]
&lt;/pre&gt;

&lt;p&gt;La conclusión clave: el typechecker es una capa de verificación que se ejecuta &lt;strong&gt;antes&lt;/strong&gt; de generar el JavaScript final. Los errores de tipo nunca llegan al runtime porque la compilación se detiene antes.&lt;/p&gt;
&lt;h2 id="el-sistema-de-tipos"&gt;El sistema de tipos&lt;/h2&gt;
&lt;p&gt;TypeScript admite tanto anotaciones de tipo explícitas como inferencia automática. Ambas estrategias coexisten en el mismo archivo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// a es number
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// b es string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;boolean&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// c es un arreglo de booleanos
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;a&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// a es number (inferido)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;b&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// b es string (inferido)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;c&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;false&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// c es boolean[] (inferido)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Apóyate en la inferencia siempre que el tipo sea evidente y reserva las anotaciones explícitas para las fronteras del sistema: firmas de funciones, APIs públicas y estructuras de datos compartidas. Esto reduce el ruido sin sacrificar seguridad.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La diferencia esencial frente a JavaScript se resume así:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Característica del sistema de tipos&lt;/th&gt;
 &lt;th&gt;JavaScript&lt;/th&gt;
 &lt;th&gt;TypeScript&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;¿Cómo se enlazan los tipos?&lt;/td&gt;
 &lt;td&gt;Dinámicamente&lt;/td&gt;
 &lt;td&gt;Estáticamente&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;¿Se convierten automáticamente?&lt;/td&gt;
 &lt;td&gt;Sí&lt;/td&gt;
 &lt;td&gt;No (en general)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;¿Cuándo se verifican?&lt;/td&gt;
 &lt;td&gt;En tiempo de ejecución&lt;/td&gt;
 &lt;td&gt;En tiempo de compilación&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;¿Cuándo afloran los errores?&lt;/td&gt;
 &lt;td&gt;En ejecución&lt;/td&gt;
 &lt;td&gt;En compilación&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="instalación-de-typescript"&gt;Instalación de TypeScript&lt;/h2&gt;
&lt;p&gt;TypeScript se distribuye como un paquete de Node, por lo que necesitas tener &lt;strong&gt;Node.js&lt;/strong&gt; instalado. Inicializa el proyecto y agrega las dependencias de desarrollo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm init -y
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install --save-dev typescript @types/node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;@types/node&lt;/code&gt; aporta las definiciones de tipos del entorno de ejecución de Node, indispensables si vas a trabajar en el backend.&lt;/p&gt;
&lt;h2 id="tsconfigjson-el-corazón-de-la-configuración"&gt;tsconfig.json: el corazón de la configuración&lt;/h2&gt;
&lt;p&gt;El archivo &lt;code&gt;tsconfig.json&lt;/code&gt;, ubicado en la raíz del proyecto, define cómo el compilador interpreta y transforma tu código. Una configuración base sólida luce así:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;es2015&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;commonjs&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;outDir&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;dist&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;sourceMap&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;strict&amp;#34;&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;target&amp;#34;&lt;/span&gt;: &lt;span style="color:#98c379"&gt;&amp;#34;es2015&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;&amp;#34;include&amp;#34;&lt;/span&gt;: [&lt;span style="color:#98c379"&gt;&amp;#34;src&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cada opción cumple un rol concreto:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;include&lt;/code&gt;: indica las rutas donde &lt;code&gt;tsc&lt;/code&gt; debe buscar los archivos a compilar.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lib&lt;/code&gt;: declara qué librerías de tipos (APIs del entorno) asume disponibles el proyecto.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;module&lt;/code&gt;: define el sistema de módulos del código emitido (&lt;code&gt;commonjs&lt;/code&gt;, &lt;code&gt;esnext&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outDir&lt;/code&gt;: ubicación de los archivos JavaScript compilados.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sourceMap&lt;/code&gt;: genera &lt;em&gt;source maps&lt;/em&gt; para depurar el TypeScript original desde el navegador o Node.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;strict&lt;/code&gt;: habilita el conjunto completo de comprobaciones estrictas. Es la opción que más valor aporta.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt;: versión de JavaScript a la que se transpila el código.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Puedes consultar el catálogo completo de opciones en la &lt;a href="https://www.typescriptlang.org/docs/handbook/compiler-options.html"




 target="_blank"
 


&gt;documentación oficial de tsc&lt;/a&gt;, o explorarlas desde la terminal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx tsc --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La opción &lt;code&gt;strict&lt;/code&gt; no es opcional en un proyecto serio. Activarla desde el primer commit evita una migración dolorosa más adelante, cuando el código ya arrastra cientos de tipos implícitos &lt;code&gt;any&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="el-archivo-de-entrada-indexts"&gt;El archivo de entrada: index.ts&lt;/h2&gt;
&lt;p&gt;El punto de entrada convencional es &lt;code&gt;src/index.ts&lt;/code&gt;. Comencemos con el clásico mensaje de prueba:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hello world from TS!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Compila el proyecto y ejecútalo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx tsc
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;node ./dist/index.js
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tsc&lt;/code&gt; lee la configuración de &lt;code&gt;tsconfig.json&lt;/code&gt;, transpila todo lo que esté bajo &lt;code&gt;src&lt;/code&gt; y deposita el resultado en &lt;code&gt;dist&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="hola-mundo-y-la-verificación-de-tipos-en-acción"&gt;Hola mundo y la verificación de tipos en acción&lt;/h2&gt;
&lt;p&gt;Observemos cómo el typechecker protege contra asignaciones inválidas:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Hola mundo&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;David Casas&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// msg = 123 // Error: number no es asignable a string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al compilar, TypeScript transpila a JavaScript plano eliminando las anotaciones:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;var&lt;/span&gt; &lt;span style="color:#e06c75"&gt;msg&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Hola mundo&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;David Casas&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;msg&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El tipo &lt;code&gt;string&lt;/code&gt; desaparece del código emitido porque su único propósito era validar en compilación. Esta propiedad —los tipos se borran tras la verificación— se conoce como &lt;em&gt;type erasure&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="watch-mode-compilación-continua"&gt;Watch mode: compilación continua&lt;/h2&gt;
&lt;p&gt;Compilar manualmente tras cada cambio rompe el flujo de trabajo. El compilador incluye un &lt;strong&gt;modo observador&lt;/strong&gt; que recompila de forma incremental cada vez que detecta una modificación:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx tsc --watch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# o su forma corta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npx tsc -w
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mantén este proceso abierto en una terminal mientras desarrollas: cada vez que guardes un archivo &lt;code&gt;.ts&lt;/code&gt;, verás de inmediato los errores de tipo o la salida actualizada en &lt;code&gt;dist&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;TypeScript no reemplaza a JavaScript; lo eleva añadiendo una capa de verificación estática que captura errores antes de ejecutar una sola línea. Con Node instalado, un &lt;code&gt;tsconfig.json&lt;/code&gt; en modo &lt;code&gt;strict&lt;/code&gt; y el compilador en &lt;em&gt;watch mode&lt;/em&gt;, ya tienes un entorno profesional listo para los siguientes temas de la serie.&lt;/p&gt;
&lt;p&gt;En el próximo artículo profundizaremos en los &lt;strong&gt;tipos básicos&lt;/strong&gt; del lenguaje: &lt;code&gt;any&lt;/code&gt;, &lt;code&gt;unknown&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt;, objetos, uniones e intersecciones.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Peticiones HTTP/AJAX con rxjs/ajax y catchError</title><link>https://blog.dacadev.com/typescript/rxjs/peticiones-ajax-rxjs/</link><pubDate>Thu, 11 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/peticiones-ajax-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende peticiones ajax rxjs con rxjs/ajax, getJSON, métodos HTTP y catchError rxjs para manejar errores en streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/ajax/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#fetch-frente-a-rxjsajax"&gt;fetch frente a rxjs/ajax&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rxjs-ajax-para-peticiones-http"&gt;rxjs ajax para peticiones HTTP&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#catcherror-rxjs-recuperar-el-stream-ante-fallos"&gt;catchError rxjs: recuperar el stream ante fallos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ajaxgetjson-para-consumir-respuestas-json"&gt;ajax.getJSON para consumir respuestas JSON&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#métodos-post-put-y-delete-con-rxjsajax"&gt;Métodos post, put y delete con rxjs/ajax&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#configuración-avanzada-con-objeto"&gt;Configuración avanzada con objeto&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#composición-con-cancelación"&gt;Composición con cancelación&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En aplicaciones frontend, las &lt;strong&gt;peticiones ajax rxjs&lt;/strong&gt; resultan útiles cuando el tráfico HTTP no es un evento aislado, sino parte de un flujo: búsquedas con cancelación, reintentos, composición con eventos de UI o coordinación entre varias fuentes asíncronas. &lt;code&gt;fetch&lt;/code&gt; cubre bien el caso imperativo basado en promesas, pero &lt;code&gt;rxjs/ajax&lt;/code&gt; integra las peticiones HTTP directamente con observables, operadores y suscripciones.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar los &lt;a href="https://blog.dacadev.com/typescript/operadores-combinacion-observables/"



 


&gt;operadores de combinación&lt;/a&gt; y cerraremos la serie abordando &lt;code&gt;rxjs/ajax&lt;/code&gt;, &lt;code&gt;ajax.getJSON&lt;/code&gt;, métodos HTTP y &lt;code&gt;catchError rxjs&lt;/code&gt; para manejar fallos sin romper el flujo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="fetch-frente-a-rxjsajax"&gt;fetch frente a rxjs/ajax&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fetch&lt;/code&gt; es el estándar moderno del navegador para ejecutar peticiones HTTP. Su API está basada en &lt;code&gt;Promise&lt;/code&gt;, por lo que encaja bien cuando necesitas una única respuesta y un flujo de control lineal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;manejaErrores&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;ok&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;throw&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;Error&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;statusText&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fetch&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;manejaErrores&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;then&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#c678dd"&gt;catch&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La limitación aparece cuando la petición debe integrarse con otros streams. Una &lt;code&gt;Promise&lt;/code&gt; no tiene el concepto de suscripción, no emite múltiples valores y no se cancela por sí misma al dejar de interesarte el resultado. &lt;code&gt;fetch&lt;/code&gt; puede abortarse con &lt;code&gt;AbortController&lt;/code&gt;, pero esa cancelación queda como una responsabilidad externa que debes coordinar manualmente.&lt;/p&gt;
&lt;p&gt;Con RxJS, en cambio, la suscripción representa el ciclo de vida del trabajo asíncrono. En &lt;code&gt;rxjs/ajax&lt;/code&gt;, cancelar la suscripción aborta la petición subyacente basada en &lt;code&gt;XMLHttpRequest&lt;/code&gt;, lo cual encaja naturalmente con operadores como &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; o &lt;code&gt;debounceTime&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;fetch&lt;/code&gt; para flujos simples basados en una sola respuesta. Usa &lt;code&gt;rxjs/ajax&lt;/code&gt; cuando la petición forma parte de una arquitectura reactiva y necesitas composición, cancelación por suscripción o manejo declarativo de errores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="rxjs-ajax-para-peticiones-http"&gt;rxjs ajax para peticiones HTTP&lt;/h2&gt;
&lt;p&gt;El módulo &lt;a href="https://rxjs.dev/api/ajax/ajax"




 target="_blank"
 


&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt;&lt;/a&gt; expone la función &lt;code&gt;ajax&lt;/code&gt;, que devuelve un observable. Al suscribirte, se ejecuta la petición; al desuscribirte, se cancela si todavía está pendiente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;login&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;html_url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;ajaxResponse&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajaxResponse&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;users&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;users&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El observable emitido por &lt;code&gt;ajax&lt;/code&gt; no entrega únicamente el cuerpo. Entrega un &lt;code&gt;AjaxResponse&amp;lt;T&amp;gt;&lt;/code&gt; con metadatos como &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;response&lt;/code&gt;, &lt;code&gt;request&lt;/code&gt; y &lt;code&gt;xhr&lt;/code&gt;. Esto es útil cuando la lógica depende del código HTTP, encabezados o detalles del transporte.&lt;/p&gt;
&lt;p&gt;Para obtener solo el cuerpo, el patrón habitual consiste en aplicar &lt;code&gt;map&lt;/code&gt; sobre &lt;code&gt;response&lt;/code&gt;. En versiones modernas de RxJS, importar operadores desde &lt;code&gt;rxjs&lt;/code&gt; mantiene el código conciso y compatible con el estilo recomendado.&lt;/p&gt;
&lt;h2 id="catcherror-rxjs-recuperar-el-stream-ante-fallos"&gt;catchError rxjs: recuperar el stream ante fallos&lt;/h2&gt;
&lt;p&gt;El operador &lt;a href="https://rxjs.dev/api/operators/catchError"




 target="_blank"
 


&gt;&lt;code&gt;catchError&lt;/code&gt;&lt;/a&gt; intercepta errores dentro de un observable y debe retornar un nuevo observable o un valor compatible con &lt;code&gt;ObservableInput&lt;/code&gt;. Esto permite reemplazar el flujo fallido por un valor seguro, reintentar con otra fuente o propagar un error enriquecido.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/ajax/marble-catcherror_hu_59aa604728b2d608.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El diagrama muestra el punto clave: cuando ocurre un error, &lt;code&gt;catchError&lt;/code&gt; reemplaza el stream original por otro observable. Si no retornas un observable, la cadena queda en un estado inválido.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;AjaxError&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;login&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://api.github.com/users?per_page=5&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;atrapaError&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;AjaxError&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([] &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;GitHubUser&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;atrapaError&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;users&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuarios&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;users&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, el consumidor siempre recibe un arreglo. Si la petición falla, la UI puede renderizar un estado vacío sin romper la suscripción. Esta decisión es adecuada para listas tolerantes a fallo, pero no para operaciones donde ocultar el error afectaría consistencia o seguridad.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/ajax/console-catcherror_hu_4f892a08d295a73c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La salida de consola confirma que el error se captura dentro del pipeline y el stream continúa con el valor de reemplazo definido por &lt;code&gt;of&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No uses &lt;code&gt;catchError&lt;/code&gt; para silenciar errores críticos de forma indiscriminada. Retorna valores de fallback solo cuando el dominio lo permite; en otros casos, transforma el error y propágalo con &lt;code&gt;throwError&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="ajaxgetjson-para-consumir-respuestas-json"&gt;ajax.getJSON para consumir respuestas JSON&lt;/h2&gt;
&lt;p&gt;Cuando solo necesitas el cuerpo JSON, &lt;code&gt;ajax.getJSON&lt;/code&gt; reduce el ruido del &lt;code&gt;AjaxResponse&lt;/code&gt;. Este método ejecuta una petición &lt;code&gt;GET&lt;/code&gt;, parsea la respuesta como JSON y permite enviar encabezados.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;DelayResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Record&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;origin&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/delay/1&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;DelayResponse&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;mi-token&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;1234&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;response$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;data&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;data&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;data&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en getJSON&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;getJSON&lt;/code&gt; es una buena opción para consultas simples donde no necesitas inspeccionar &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;xhr&lt;/code&gt; o encabezados de respuesta. Si esos metadatos importan, usa &lt;code&gt;ajax&lt;/code&gt; directamente para conservar el contexto completo.&lt;/p&gt;
&lt;h2 id="métodos-post-put-y-delete-con-rxjsajax"&gt;Métodos post, put y delete con rxjs/ajax&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt; también expone métodos especializados para verbos HTTP comunes: &lt;code&gt;ajax.get&lt;/code&gt;, &lt;code&gt;ajax.post&lt;/code&gt;, &lt;code&gt;ajax.put&lt;/code&gt;, &lt;code&gt;ajax.patch&lt;/code&gt; y &lt;code&gt;ajax.delete&lt;/code&gt;. Todos retornan observables y pueden participar en el mismo pipeline de operadores.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;T&lt;/span&gt;&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;json&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;T&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/anything/users&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;x-client&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs-demo&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt;&amp;gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, { &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Ada&amp;#39;&lt;/span&gt; }, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en POST&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;put&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HttpBinResponse&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;UserPayload&lt;/span&gt;&amp;gt;&amp;gt;(&lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;/1`&lt;/span&gt;, { &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Ada Lovelace&amp;#39;&lt;/span&gt; }, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;PUT&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en PUT&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;delete&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;/1`&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;DELETE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error en DELETE&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La forma especializada es legible cuando el método HTTP es fijo y la configuración es pequeña. Para casos con más parámetros, la forma de objeto suele ser más mantenible.&lt;/p&gt;
&lt;h2 id="configuración-avanzada-con-objeto"&gt;Configuración avanzada con objeto&lt;/h2&gt;
&lt;p&gt;La función &lt;code&gt;ajax&lt;/code&gt; acepta un objeto de configuración. Esta variante agrupa &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;responseType&lt;/code&gt; y otros parámetros en una sola estructura, evitando firmas largas y facilitando la composición dinámica.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CreateUserRequest&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;role&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;editor&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;viewer&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;CreateUserResponse&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;json&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;CreateUserRequest&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requestBody&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;CreateUserRequest&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Grace Hopper&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;role&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;admin&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;createUser$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;CreateUserResponse&lt;/span&gt;&amp;gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://httpbin.org/anything/users&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;method&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;Authorization&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Bearer demo-token&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;body&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;requestBody&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;responseType&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;json&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;warn&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;No fue posible crear el usuario&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;null&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;createUser$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;usuario creado&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta forma es especialmente útil en servicios donde construyes peticiones desde parámetros de dominio. También facilita extraer una función reutilizable que retorne un observable tipado sin ejecutar la petición hasta que exista una suscripción.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mantén las funciones HTTP como fábricas de observables: reciben parámetros de dominio y retornan &lt;code&gt;Observable&amp;lt;T&amp;gt;&lt;/code&gt;. Evita suscribirte dentro del servicio si el consumidor necesita cancelar, componer o manejar errores en una capa superior.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="composición-con-cancelación"&gt;Composición con cancelación&lt;/h2&gt;
&lt;p&gt;Una de las ventajas prácticas de &lt;code&gt;rxjs/ajax&lt;/code&gt; aparece en búsquedas o autocompletados. &lt;code&gt;switchMap&lt;/code&gt; cancela la petición anterior cuando llega un nuevo término, evitando condiciones de carrera y respuestas obsoletas.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; (&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;unknown&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;catchError&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([])),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;results$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;renderResults&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con &lt;code&gt;fetch&lt;/code&gt;, este patrón requiere coordinar manualmente &lt;code&gt;AbortController&lt;/code&gt; para cada búsqueda pendiente. Con RxJS, la cancelación es una consecuencia directa de la desuscripción que &lt;code&gt;switchMap&lt;/code&gt; realiza sobre el observable interno anterior.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rxjs/ajax&lt;/code&gt; convierte las peticiones HTTP en streams composables. Esta integración permite mapear respuestas, centralizar errores con &lt;code&gt;catchError&lt;/code&gt;, cancelar trabajo pendiente mediante desuscripción y coordinar tráfico HTTP con eventos de interfaz o temporizadores.&lt;/p&gt;
&lt;p&gt;Con este artículo cerramos la serie RxJs: partimos de la naturaleza de los observables, recorrimos funciones de creación, operadores básicos, transformación, combinación y finalmente peticiones AJAX. El objetivo común fue diseñar flujos asíncronos explícitos, cancelables y mantenibles usando las primitivas reactivas correctas.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de combinación de observables</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-combinacion-observables/</link><pubDate>Tue, 09 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-combinacion-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a combinar observables RxJS con startWith, endWith, concat, merge, combineLatest y forkJoin en flujos reactivos reales.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#startwith-inicializar-un-observable-con-una-primera-emisión"&gt;&lt;code&gt;startWith&lt;/code&gt;: inicializar un observable con una primera emisión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#endwith-añadir-emisiones-al-completar-el-stream"&gt;&lt;code&gt;endWith&lt;/code&gt;: añadir emisiones al completar el stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#concat-combinar-observables-rxjs-de-forma-secuencial"&gt;&lt;code&gt;concat&lt;/code&gt;: combinar observables RxJS de forma secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#merge-combinar-emisiones-concurrentes-en-un-solo-observable"&gt;&lt;code&gt;merge&lt;/code&gt;: combinar emisiones concurrentes en un solo observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#combinelatest-sincronizar-los-últimos-valores-emitidos"&gt;&lt;code&gt;combineLatest&lt;/code&gt;: sincronizar los últimos valores emitidos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#forkjoin-esperar-la-última-emisión-de-observables-finitos"&gt;&lt;code&gt;forkJoin&lt;/code&gt;: esperar la última emisión de observables finitos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-elegir-entre-concat-merge-combinelatest-y-forkjoin"&gt;Cómo elegir entre &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando una aplicación reactiva necesita coordinar eventos de teclado, clics, respuestas HTTP y temporizadores, el reto no está solo en crear observables, sino en decidir cómo sincronizar sus emisiones. &lt;strong&gt;Combinar observables RxJS&lt;/strong&gt; correctamente evita acoplamiento innecesario, carreras difíciles de depurar y estados intermedios inconsistentes en la interfaz.&lt;/p&gt;
&lt;p&gt;En este artículo analizaremos operadores y funciones de combinación de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;: &lt;code&gt;startWith&lt;/code&gt;, &lt;code&gt;endWith&lt;/code&gt;, &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;. Cada uno resuelve un problema distinto: inicializar un stream, añadir una emisión final, concatenar secuencias, mezclar eventos concurrentes, sincronizar últimos valores o esperar a que varias fuentes finalicen.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de revisar &lt;a href="https://blog.dacadev.com/typescript/operadores-no-tan-comunes-rxjs/"



 


&gt;Operadores no tan comunes&lt;/a&gt; y después continuaremos con &lt;a href="https://blog.dacadev.com/typescript/peticiones-ajax-rxjs/"



 


&gt;Ajax con RxJs&lt;/a&gt;. Aquí nos enfocamos en operadores de combinación y en cómo elegir el adecuado según el comportamiento esperado del flujo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="startwith-inicializar-un-observable-con-una-primera-emisión"&gt;&lt;code&gt;startWith&lt;/code&gt;: inicializar un observable con una primera emisión&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;startWith&lt;/code&gt;&lt;/strong&gt; permite definir una o varias emisiones iniciales antes de que el observable fuente empiece a entregar sus propios valores. Es útil cuando una suscripción necesita un estado inicial inmediato, por ejemplo, para pintar una vista antes de que ocurra el primer evento real.&lt;/p&gt;
&lt;p&gt;En el diagrama, el valor &lt;code&gt;a&lt;/code&gt; se emite antes que cualquier valor proveniente del observable original. La suscripción no necesita esperar a que la fuente produzca el primer dato.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-startwith_hu_3f50febfe8c561c5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Ejemplo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Este flujo primero emite &lt;code&gt;3&lt;/code&gt; por efecto de &lt;code&gt;startWith(3)&lt;/code&gt; y después continúa con las emisiones de &lt;code&gt;of(1, 2, 3)&lt;/code&gt;. En escenarios de UI, este patrón suele aparecer cuando necesitas mostrar un valor por defecto antes de recibir eventos del usuario o datos remotos.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;startWith&lt;/code&gt; no modifica la fuente original; crea un nuevo observable con emisiones prefijadas. Esta distinción mantiene la composición declarativa del pipeline.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="endwith-añadir-emisiones-al-completar-el-stream"&gt;&lt;code&gt;endWith&lt;/code&gt;: añadir emisiones al completar el stream&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;endWith&lt;/code&gt;&lt;/strong&gt; trabaja en el extremo opuesto de &lt;code&gt;startWith&lt;/code&gt;. En lugar de emitir valores al inicio, agrega emisiones al final, justo cuando el observable fuente completa.&lt;/p&gt;
&lt;p&gt;Esto implica una condición importante: la fuente debe completar. Si el observable nunca envía la señal de &lt;code&gt;complete&lt;/code&gt;, &lt;code&gt;endWith&lt;/code&gt; no tendrá oportunidad de emitir sus valores finales.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-endwith_hu_1dbaa30bd447d3be.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El modo de uso puede combinar ambos operadores:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;endWith&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;startWith&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;endWith&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;y&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado incluye las emisiones iniciales, los valores originales y las emisiones finales:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-start-endwith_hu_2d98486731811f2a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;endWith&lt;/code&gt; es apropiado para flujos finitos donde quieres señalar un cierre lógico, adjuntar un marcador final o emitir un estado de terminación después de procesar una secuencia.&lt;/p&gt;
&lt;h2 id="concat-combinar-observables-rxjs-de-forma-secuencial"&gt;&lt;code&gt;concat&lt;/code&gt;: combinar observables RxJS de forma secuencial&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;concat&lt;/code&gt;&lt;/strong&gt; concatena observables uno detrás de otro. Se suscribe al primer observable, espera a que complete y solo entonces avanza al siguiente. El resultado es un observable nuevo que conserva el orden secuencial de las fuentes.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;concat&lt;/code&gt; es una función de creación/combinación; no debe confundirse con &lt;code&gt;concatMap&lt;/code&gt;. &lt;code&gt;concatMap&lt;/code&gt; proyecta cada emisión hacia un observable interno y los aplana en orden. &lt;code&gt;concat&lt;/code&gt;, en cambio, recibe fuentes ya definidas y las ejecuta secuencialmente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El diagrama muestra que las emisiones del segundo stream no empiezan hasta que el primero completa. Esta propiedad es crítica cuando el orden tiene semántica de negocio, por ejemplo, inicializar una configuración antes de consumir un flujo dependiente.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-concat_hu_ee64538cd07c1214.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Su modo de uso es:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;concat&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;concat&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;// un iterable u objeto compatible con ObservableInput
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El primer &lt;code&gt;intervalo$.pipe(take(2))&lt;/code&gt; emite dos valores y completa. Después se ejecuta el segundo &lt;code&gt;intervalo$.pipe(take(3))&lt;/code&gt;. Finalmente, &lt;code&gt;concat&lt;/code&gt; consume el arreglo &lt;code&gt;[1, 2, 3, 5]&lt;/code&gt; como una fuente compatible con &lt;code&gt;ObservableInput&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;El resultado respeta ese orden:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-concat_hu_4f320d74fd3067a2.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La restricción operativa más importante es que cada fuente debe completar para que &lt;code&gt;concat&lt;/code&gt; avance. Si el primer observable es infinito, el segundo nunca se suscribirá.&lt;/p&gt;
&lt;h2 id="merge-combinar-emisiones-concurrentes-en-un-solo-observable"&gt;&lt;code&gt;merge&lt;/code&gt;: combinar emisiones concurrentes en un solo observable&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/strong&gt; combina las emisiones de dos o más observables en un único stream de salida. A diferencia de &lt;code&gt;concat&lt;/code&gt;, no espera a que una fuente complete para suscribirse a la siguiente; todas las fuentes activas pueden emitir de forma concurrente.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; completa únicamente cuando todos los observables de entrada han completado. En streams de eventos del DOM, como &lt;code&gt;click&lt;/code&gt; o &lt;code&gt;keyup&lt;/code&gt;, esto normalmente significa que el flujo permanece activo durante toda la vida de la página, salvo que se aplique una estrategia de finalización explícita.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-merge_hu_2109f797e699b06b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Modo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;merge&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;merge&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso, ambos observables se transforman para emitir únicamente el tipo de evento. El stream resultante recibe tanto &lt;code&gt;keyup&lt;/code&gt; como &lt;code&gt;click&lt;/code&gt;, sin imponer un orden artificial entre ellos.&lt;/p&gt;
&lt;p&gt;El resultado en consola evidencia que ambos eventos se combinan en una sola suscripción:&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/console-merge-events_hu_13a76b79f5c14923.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;merge&lt;/code&gt; es una buena elección cuando las fuentes son independientes y quieres reaccionar a cualquiera de ellas con la misma lógica de downstream.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="combinelatest-sincronizar-los-últimos-valores-emitidos"&gt;&lt;code&gt;combineLatest&lt;/code&gt;: sincronizar los últimos valores emitidos&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt; combina múltiples observables y emite un arreglo con el último valor disponible de cada fuente. Su comportamiento tiene una regla clave: no emite hasta que todos los observables participantes hayan emitido al menos una vez.&lt;/p&gt;
&lt;p&gt;Después de esa primera sincronización, cada nueva emisión de cualquier fuente produce una nueva salida con el valor actualizado de esa fuente y los últimos valores conocidos de las demás. Esto es especialmente útil para formularios, filtros, coordenadas de UI y estados derivados.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-combinelatest_hu_5536863cb22096a9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El código de uso puede ser parecido a esto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;placeholder&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;email@example.com&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;placeholder&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;*******&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;.&lt;span style="color:#c678dd"&gt;type&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// helper
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;elem&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;HTMLElement&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;elem&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El ejemplo conserva la firma posicional usada durante mucho tiempo en RxJS. En código moderno, especialmente con RxJS 7+, suele preferirse la firma con arreglo porque escala mejor y es más explícita:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;combineLatest&lt;/span&gt;([
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;getInputString&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input2&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;También conviene considerar que &lt;code&gt;pluck&lt;/code&gt; pertenece a un estilo más antiguo de transformación. Para proyectos nuevos, &lt;code&gt;map&lt;/code&gt; con acceso explícito suele ser más legible y compatible con la evolución del ecosistema.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si una de las fuentes de &lt;code&gt;combineLatest&lt;/code&gt; nunca emite, el observable combinado tampoco emitirá. Para evitar estados bloqueados, puedes inicializar fuentes con &lt;code&gt;startWith&lt;/code&gt; cuando tenga sentido semántico.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="forkjoin-esperar-la-última-emisión-de-observables-finitos"&gt;&lt;code&gt;forkJoin&lt;/code&gt;: esperar la última emisión de observables finitos&lt;/h2&gt;
&lt;p&gt;La función &lt;strong&gt;&lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt; emite una sola vez con la última emisión de cada observable de entrada, pero únicamente cuando todos completan. Este comportamiento la convierte en una herramienta precisa para coordinar operaciones finitas, como peticiones HTTP simultáneas.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Los observables pasados a &lt;code&gt;forkJoin&lt;/code&gt; deben ser finitos. Si alguno nunca completa, &lt;code&gt;forkJoin&lt;/code&gt; nunca emitirá resultado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El diagrama muestra que la salida aparece al final, cuando todas las fuentes han completado y existe un último valor para cada una.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/combination-operators/marble-forkjoin_hu_21713f02bc2dcb9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Modo de uso:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;forkJoin&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;letras$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3500&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// ).subscribe(console.log);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin(
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// ).subscribe(resp =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;numeros&amp;#39;, resp[0]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;intervalo&amp;#39;, resp[1]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(&amp;#39;letras&amp;#39;, resp[2]);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// forkJoin({
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// numeros$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// intervalo$,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// letras$
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// }).subscribe(resp =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// console.log(resp);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;forkJoin&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;numeros$&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;int&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;intervalo$&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;letras$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resp&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resp&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La forma con objeto es especialmente práctica porque conserva nombres semánticos en la respuesta. En lugar de depender de índices como &lt;code&gt;resp[0]&lt;/code&gt;, &lt;code&gt;resp[1]&lt;/code&gt; o &lt;code&gt;resp[2]&lt;/code&gt;, el consumidor trabaja con propiedades explícitas: &lt;code&gt;num&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt; y &lt;code&gt;let&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;El uso más común de &lt;code&gt;forkJoin&lt;/code&gt; aparece cuando haces peticiones AJAX simultáneas y necesitas continuar solo cuando todas han terminado correctamente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cómo-elegir-entre-concat-merge-combinelatest-y-forkjoin"&gt;Cómo elegir entre &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt; y &lt;code&gt;forkJoin&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Estos operadores pueden parecer similares porque todos combinan fuentes, pero su semántica de tiempo es distinta:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;concat&lt;/code&gt;&lt;/strong&gt; cuando el orden secuencial sea obligatorio y cada fuente deba completar antes de iniciar la siguiente.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/strong&gt; cuando las fuentes sean independientes y quieras reaccionar a cualquiera de ellas tan pronto como emita.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;combineLatest&lt;/code&gt;&lt;/strong&gt; cuando necesites calcular estado derivado a partir del último valor conocido de varias fuentes activas.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;forkJoin&lt;/code&gt;&lt;/strong&gt; cuando esperes observables finitos y solo necesites el resultado final de cada uno.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;&lt;code&gt;startWith&lt;/code&gt;&lt;/strong&gt; y &lt;strong&gt;&lt;code&gt;endWith&lt;/code&gt;&lt;/strong&gt; para insertar emisiones de inicio o cierre dentro de un pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Esta elección tiene impacto directo en latencia, orden de ejecución y condiciones de completado. En sistemas reactivos, estos detalles definen si el flujo se mantiene responsivo o si queda bloqueado esperando una emisión que nunca llega.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Combinar observables RxJS requiere distinguir entre concurrencia, secuencialidad y sincronización de valores. &lt;code&gt;concat&lt;/code&gt; serializa fuentes, &lt;code&gt;merge&lt;/code&gt; las mezcla, &lt;code&gt;combineLatest&lt;/code&gt; deriva estado desde los últimos valores y &lt;code&gt;forkJoin&lt;/code&gt; espera resultados finales de observables finitos.&lt;/p&gt;
&lt;p&gt;Dominar estas diferencias permite diseñar pipelines más predecibles y expresivos. En el siguiente artículo aplicaremos estos conceptos al trabajo con peticiones AJAX, donde &lt;code&gt;forkJoin&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt; y otros operadores empiezan a interactuar con latencia real de red y manejo de errores.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores no tan comunes</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-no-tan-comunes-rxjs/</link><pubDate>Sun, 07 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-no-tan-comunes-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores rxjs menos frecuentes como take, first, takeWhile, takeUntil, skip, distinct y distinctUntilChanged.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#take-limitar-emisiones-de-un-observable"&gt;&lt;code&gt;take&lt;/code&gt;: limitar emisiones de un Observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#first-tomar-la-primera-emisión-o-la-primera-que-cumpla-una-condición"&gt;&lt;code&gt;first&lt;/code&gt;: tomar la primera emisión o la primera que cumpla una condición&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#first-con-predicado"&gt;&lt;code&gt;first&lt;/code&gt; con predicado&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#takewhile-emitir-mientras-se-mantenga-una-condición"&gt;&lt;code&gt;takeWhile&lt;/code&gt;: emitir mientras se mantenga una condición&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#takeuntil-cancelar-un-flujo-con-otro-observable"&gt;&lt;code&gt;takeUntil&lt;/code&gt;: cancelar un flujo con otro Observable&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#skip-omitir-emisiones-iniciales"&gt;&lt;code&gt;skip&lt;/code&gt;: omitir emisiones iniciales&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinct-eliminar-valores-repetidos-globalmente"&gt;&lt;code&gt;distinct&lt;/code&gt;: eliminar valores repetidos globalmente&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#distinct-con-selector-para-objetos"&gt;&lt;code&gt;distinct&lt;/code&gt; con selector para objetos&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinctuntilchanged-evitar-repeticiones-consecutivas"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt;: evitar repeticiones consecutivas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#distinctuntilchanged-con-comparador"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; con comparador&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#distinctuntilkeychanged-comparación-consecutiva-por-propiedad"&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;: comparación consecutiva por propiedad&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En flujos reactivos de interfaz, temporizadores o eventos del DOM, no siempre necesitas transformar cada emisión. Con frecuencia el problema operativo consiste en limitar una suscripción, cancelar un &lt;code&gt;Observable&lt;/code&gt; ante una señal externa o eliminar emisiones repetidas. Estos &lt;strong&gt;operadores RxJS&lt;/strong&gt; resuelven ese tipo de control sin introducir estado mutable adicional ni lógica imperativa alrededor de la suscripción.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de revisar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-transformacion-rxjs/"



 


&gt;operadores de transformación&lt;/a&gt; y aquí analizaremos &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;takeWhile&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt; y &lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;. El siguiente artículo aborda los &lt;a href="https://blog.dacadev.com/typescript/operadores-combinacion-observables/"



 


&gt;operadores de combinación&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La referencia formal de estos operadores está en la documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; y en el modelo conceptual de &lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;ReactiveX&lt;/a&gt;. En este artículo nos concentraremos en su comportamiento práctico, especialmente en cuándo completan el flujo y cómo comparan valores.&lt;/p&gt;
&lt;h2 id="take-limitar-emisiones-de-un-observable"&gt;&lt;code&gt;take&lt;/code&gt;: limitar emisiones de un Observable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;take&lt;/code&gt; permite definir cuántas emisiones del &lt;code&gt;Observable&lt;/code&gt; fuente queremos recibir. Una vez alcanza ese límite, el operador completa la cadena y cancela la suscripción aguas arriba.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-take_hu_18c316156fc7352b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este patrón es útil cuando el consumidor solo necesita una muestra finita de un flujo potencialmente largo, como los primeros eventos, los primeros valores de un intervalo o una respuesta inicial.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El &lt;code&gt;tap&lt;/code&gt; se ejecuta solo para los valores que alcanzan la suscripción antes de que &lt;code&gt;take(3)&lt;/code&gt; complete el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-take_hu_acbd9bad5d1f147f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;take&lt;/code&gt; es una forma declarativa de evitar suscripciones más largas de lo necesario. En flujos infinitos como &lt;code&gt;interval&lt;/code&gt;, puede prevenir fugas si el ciclo de vida esperado es finito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="first-tomar-la-primera-emisión-o-la-primera-que-cumpla-una-condición"&gt;&lt;code&gt;first&lt;/code&gt;: tomar la primera emisión o la primera que cumpla una condición&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;first&lt;/code&gt; obtiene la primera emisión del &lt;code&gt;Observable&lt;/code&gt; y completa la suscripción. Su caso básico se parece a &lt;code&gt;take(1)&lt;/code&gt;, pero también acepta un predicado para esperar la primera emisión que cumpla una condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-first_hu_b57c6c3a31077d9a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;first&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;first&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Después del primer clic, el flujo completa y deja de escuchar nuevos eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-first_hu_7c4360a367784e09.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="first-con-predicado"&gt;&lt;code&gt;first&lt;/code&gt; con predicado&lt;/h3&gt;
&lt;p&gt;Cuando &lt;code&gt;first&lt;/code&gt; recibe un predicado, ignora las emisiones previas hasta encontrar la primera que devuelva &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;first&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;first&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;clientY&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;150&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El &lt;code&gt;tap&lt;/code&gt; confirma que el flujo sigue recibiendo clics, pero &lt;code&gt;first&lt;/code&gt; solo emite cuando la coordenada &lt;code&gt;clientY&lt;/code&gt; cumple la condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-first-predicate_hu_dd483944bae9057f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si la fuente completa sin que el predicado de &lt;code&gt;first&lt;/code&gt; se cumpla, RxJS puede emitir un error &lt;code&gt;EmptyError&lt;/code&gt;. Considera un valor por defecto o un operador alternativo cuando ese escenario sea válido.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="takewhile-emitir-mientras-se-mantenga-una-condición"&gt;&lt;code&gt;takeWhile&lt;/code&gt;: emitir mientras se mantenga una condición&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;takeWhile&lt;/code&gt; mantiene la suscripción activa mientras el predicado devuelva &lt;code&gt;true&lt;/code&gt;. En cuanto una emisión no cumple la condición, el operador completa el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-takewhile_hu_e42f671167cc2913.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo tomamos clics mientras la coordenada &lt;code&gt;y&lt;/code&gt; sea menor o igual a &lt;code&gt;150&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;takeWhile&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;takeWhile&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;150&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;coords&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;coords&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El segundo argumento, conocido como bandera &lt;strong&gt;inclusive&lt;/strong&gt;, indica si la emisión que rompe la condición también debe enviarse al suscriptor. Por defecto es &lt;code&gt;false&lt;/code&gt;; con &lt;code&gt;true&lt;/code&gt;, el valor que provoca el cierre se conserva.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-takewhile-inclusive_hu_e080f0a7ac2ad474.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;takeWhile&lt;/code&gt; modela límites basados en datos. Es diferente de &lt;code&gt;filter&lt;/code&gt;: &lt;code&gt;filter&lt;/code&gt; descarta valores y continúa; &lt;code&gt;takeWhile&lt;/code&gt; completa el flujo cuando la condición deja de cumplirse.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="takeuntil-cancelar-un-flujo-con-otro-observable"&gt;&lt;code&gt;takeUntil&lt;/code&gt;: cancelar un flujo con otro Observable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;takeUntil&lt;/code&gt; recibe un segundo &lt;code&gt;Observable&lt;/code&gt;, llamado normalmente &lt;code&gt;notifier&lt;/code&gt;. El flujo principal emite hasta que ese &lt;code&gt;notifier&lt;/code&gt; produce su primera emisión; en ese momento la cadena completa.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-takeuntil_hu_cdc0acc3e1676e92.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este patrón es común para cancelar intervalos, peticiones, listeners o cualquier proceso reactivo asociado al ciclo de vida de un componente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;boton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;button&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;innerHTML&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Detener timing&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;)).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El contador sigue emitiendo cada segundo hasta que el botón produce un evento &lt;code&gt;click&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-takeuntil_hu_b86b54f77e79792e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En aplicaciones con componentes, &lt;code&gt;takeUntil&lt;/code&gt; suele conectarse a una señal de destrucción para liberar recursos y cerrar suscripciones de forma predecible.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="skip-omitir-emisiones-iniciales"&gt;&lt;code&gt;skip&lt;/code&gt;: omitir emisiones iniciales&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;skip&lt;/code&gt; ignora las primeras &lt;code&gt;n&lt;/code&gt; emisiones del &lt;code&gt;Observable&lt;/code&gt; fuente y deja pasar las posteriores. Es útil cuando las primeras señales representan inicialización, ruido operativo o eventos que no deben activar la lógica principal.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-skip_hu_34ae533aa471be84.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Aplicado al ejemplo anterior, podemos exigir varios clics antes de cancelar el contador. Con &lt;code&gt;skip(2)&lt;/code&gt;, el tercer clic es el primero que llega a &lt;code&gt;takeUntil&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;skip&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;boton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;button&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;innerHTML&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Detener timing&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;body&amp;#34;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;?&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;append&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;boton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;click&amp;#34;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap-antes&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;skip&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;tap-despues&amp;#34;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;takeUntil&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;)).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La salida muestra que los primeros clics existen, pero no cruzan la frontera marcada por &lt;code&gt;skip&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-skip_hu_47b321fbdd1deba4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="distinct-eliminar-valores-repetidos-globalmente"&gt;&lt;code&gt;distinct&lt;/code&gt;: eliminar valores repetidos globalmente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinct&lt;/code&gt; evita que el flujo emita valores ya observados previamente. La comparación base usa igualdad estricta (&lt;code&gt;===&lt;/code&gt;), por lo que tipo y valor deben coincidir.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinct_hu_c01e49d9695a2ef6.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El operador conserva una memoria interna de valores ya emitidos y descarta repeticiones posteriores.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinct_hu_936aafc688e819b5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="distinct-con-selector-para-objetos"&gt;&lt;code&gt;distinct&lt;/code&gt; con selector para objetos&lt;/h3&gt;
&lt;p&gt;Con objetos, dos instancias con la misma estructura no son iguales por referencia. Para resolverlo, &lt;code&gt;distinct&lt;/code&gt; acepta un selector que define la clave de comparación.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinct&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso la unicidad se calcula por &lt;code&gt;nombre&lt;/code&gt;, no por referencia del objeto.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinct-selector_hu_e2d36d92979adb21.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;distinct&lt;/code&gt; mantiene un registro de claves ya vistas. En flujos largos o infinitos, evalúa el impacto en memoria o usa una estrategia con cierre explícito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="distinctuntilchanged-evitar-repeticiones-consecutivas"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt;: evitar repeticiones consecutivas&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; compara cada emisión con la emisión inmediatamente anterior. Solo descarta duplicados consecutivos; si un valor reaparece más adelante después de otro valor distinto, puede emitirse de nuevo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinctuntilchanged_hu_910145903f00acd.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numeros$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La igualdad por defecto también usa &lt;code&gt;===&lt;/code&gt;; por eso &lt;code&gt;1&lt;/code&gt; y &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt; no se consideran duplicados.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilchanged_hu_c13ce3b955e241eb.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="distinctuntilchanged-con-comparador"&gt;&lt;code&gt;distinctUntilChanged&lt;/code&gt; con comparador&lt;/h3&gt;
&lt;p&gt;Para objetos, el comparador recibe el valor anterior y el actual. Debe retornar &lt;code&gt;true&lt;/code&gt; cuando ambos se consideran equivalentes y, por tanto, el valor actual debe omitirse.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;anterior&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;actual&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;anterior&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#e06c75"&gt;actual&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El flujo descarta únicamente los personajes consecutivos con el mismo &lt;code&gt;nombre&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilchanged-comparator_hu_f501dff0424ef24d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="distinctuntilkeychanged-comparación-consecutiva-por-propiedad"&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt;: comparación consecutiva por propiedad&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;distinctUntilKeyChanged&lt;/code&gt; aplica la misma idea de &lt;code&gt;distinctUntilChanged&lt;/code&gt;, pero optimizada para objetos cuando la comparación depende de una propiedad concreta.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/marble-distinctuntilkeychanged_hu_502038a9e4c7fbd7.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilKeyChanged&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;rxjs/operators&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Zero&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;X&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#34;Megaman&amp;#34;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;distinctUntilKeyChanged&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;nombre&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La intención queda más explícita que con un comparador manual cuando solo necesitas evaluar una clave.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/uncommon-operators/console-distinctuntilkeychanged_hu_a313d9c96362d79c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Estos operadores no son secundarios; resuelven decisiones críticas de ciclo de vida, cancelación y deduplicación en flujos reactivos. &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;first&lt;/code&gt;, &lt;code&gt;takeWhile&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; y &lt;code&gt;skip&lt;/code&gt; controlan cuántas emisiones llegan al consumidor y cuándo termina la suscripción. &lt;code&gt;distinct&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt; y &lt;code&gt;distinctUntilKeyChanged&lt;/code&gt; controlan repetición y semántica de igualdad.&lt;/p&gt;
&lt;p&gt;La regla práctica es seleccionar el operador según el límite que necesitas expresar: cantidad, condición, señal externa, emisiones iniciales o duplicados. Esa precisión mantiene tus pipelines de RxJS más declarativos, auditables y fáciles de mantener.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de transformación</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-de-transformacion-rxjs/</link><pubDate>Fri, 05 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-de-transformacion-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores de transformación RxJS para aplanar flujos con mergeAll, mergeMap, switchMap, concatMap y exhaustMap.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#mergeall-aplanar-observables-internos-con-concurrencia"&gt;&lt;code&gt;mergeAll&lt;/code&gt;: aplanar observables internos con concurrencia&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#mergemap-transformar-y-mezclar-con-concurrencia-completa"&gt;&lt;code&gt;mergeMap&lt;/code&gt;: transformar y mezclar con concurrencia completa&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#switchmap-cancelar-lo-anterior-y-conservar-lo-más-reciente"&gt;&lt;code&gt;switchMap&lt;/code&gt;: cancelar lo anterior y conservar lo más reciente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#concatmap-preservar-orden-y-ejecutar-de-forma-secuencial"&gt;&lt;code&gt;concatMap&lt;/code&gt;: preservar orden y ejecutar de forma secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#exhaustmap-ignorar-nuevas-emisiones-mientras-hay-trabajo-activo"&gt;&lt;code&gt;exhaustMap&lt;/code&gt;: ignorar nuevas emisiones mientras hay trabajo activo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuándo-elegir-cada-operador-de-transformación-rxjs"&gt;Cuándo elegir cada operador de transformación RxJS&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando una aplicación combina eventos de UI, peticiones HTTP y procesos asíncronos, el flujo deja de ser una secuencia plana de valores y empieza a producir &lt;strong&gt;observables internos&lt;/strong&gt;. Los &lt;strong&gt;operadores de transformación RxJS&lt;/strong&gt; resuelven ese punto crítico: convierten un observable de observables en un flujo consumible, controlando concurrencia, cancelación, orden y exclusión de trabajo duplicado.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-tiempo-rxjs/"



 


&gt;Operadores de tiempo&lt;/a&gt; y aquí abordaremos &lt;code&gt;mergeAll&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;concatMap&lt;/code&gt; y &lt;code&gt;exhaustMap&lt;/code&gt;; después continuaremos con &lt;a href="https://blog.dacadev.com/typescript/operadores-no-tan-comunes-rxjs/"



 


&gt;Operadores no tan comunes&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; describe estos operadores como herramientas para trabajar con &lt;strong&gt;higher-order observables&lt;/strong&gt;: observables cuyas emisiones son, a su vez, otros observables. En términos prácticos, aparecen cada vez que un evento dispara trabajo asíncrono: una búsqueda, un guardado, una carga incremental o una operación remota.&lt;/p&gt;
&lt;p&gt;La diferencia entre estos operadores no es cosmética. Elegir uno u otro define cómo se comporta el sistema ante emisiones rápidas: si ejecuta todo en paralelo, cancela lo anterior, serializa las tareas o ignora nuevos eventos mientras una operación sigue activa.&lt;/p&gt;
&lt;h2 id="mergeall-aplanar-observables-internos-con-concurrencia"&gt;&lt;code&gt;mergeAll&lt;/code&gt;: aplanar observables internos con concurrencia&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mergeAll&lt;/code&gt; trabaja sobre un observable que emite observables. Se suscribe a cada observable interno y reemite sus valores en el flujo resultante. El resultado se completa únicamente cuando el observable exterior se completa y todos los observables internos activos también han completado.&lt;/p&gt;
&lt;p&gt;Este operador es útil cuando ya tienes construidos los observables internos y solo necesitas aplanarlos. Por ejemplo, una capa previa puede generar varias operaciones independientes: guardar un borrador, registrar auditoría y sincronizar métricas. Si ninguna depende del resultado de la otra, &lt;code&gt;mergeAll&lt;/code&gt; permite ejecutarlas con concurrencia.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-mergeall_hu_994d656b4b603393.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En el diagrama, cada emisión del flujo superior representa un observable interno. &lt;code&gt;mergeAll&lt;/code&gt; mezcla sus emisiones conforme llegan, sin preservar necesariamente el orden original entre observables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mergeAll&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saveDraft$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;draft saved&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sendAudit$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;100&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;audit sent&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;syncMetrics$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;200&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;metrics synced&amp;#39;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;([&lt;span style="color:#e06c75"&gt;saveDraft$&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;sendAudit$&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;syncMetrics$&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mergeAll&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// audit sent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// metrics synced
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// draft saved
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El ejemplo muestra un comportamiento clave: el orden de salida depende del tiempo de finalización de cada observable interno. Si necesitas preservar orden estricto, &lt;code&gt;mergeAll&lt;/code&gt; no es la herramienta adecuada; &lt;code&gt;concatMap&lt;/code&gt; encaja mejor en ese caso.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;mergeAll&lt;/code&gt; cuando ya tienes observables internos construidos y deseas aplanarlos. Si primero necesitas transformar cada valor del flujo exterior en un observable, normalmente &lt;code&gt;mergeMap&lt;/code&gt; expresa mejor la intención.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="mergemap-transformar-y-mezclar-con-concurrencia-completa"&gt;&lt;code&gt;mergeMap&lt;/code&gt;: transformar y mezclar con concurrencia completa&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;mergeMap&lt;/code&gt; combina dos pasos: transforma cada emisión del observable fuente en un observable interno y luego mezcla las emisiones de todos esos observables. Conceptualmente equivale a aplicar &lt;code&gt;map&lt;/code&gt; para crear observables y después &lt;code&gt;mergeAll&lt;/code&gt; para aplanarlos.&lt;/p&gt;
&lt;p&gt;Su semántica favorece la concurrencia. Cada emisión entrante dispara una nueva suscripción interna, y las suscripciones anteriores permanecen activas hasta completar. Esto lo hace adecuado para operaciones independientes donde cancelar trabajo previo sería incorrecto, como escrituras, telemetría, cargas paralelas o procesamiento de elementos sin dependencia de orden.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-mergemap_hu_8f747c544c480b92.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mergeMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;name&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;userIds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;101&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;102&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;103&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;104&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;userIds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mergeMap&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;User&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/users/&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;id&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#d19a66"&gt;4&lt;/span&gt; &lt;span style="color:#7f848e"&gt;// límite de concurrencia
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;user&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Usuario cargado:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;user&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aunque &lt;code&gt;mergeMap&lt;/code&gt; suele asociarse con “concurrencia completa”, RxJS permite limitar esa concurrencia con el segundo argumento. Este detalle es importante cuando el flujo fuente puede emitir muchos valores y cada valor dispara trabajo costoso, como peticiones HTTP o acceso a recursos externos.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;mergeMap&lt;/code&gt; no cancela observables internos anteriores. Si el flujo fuente emite más rápido de lo que los internos completan, puedes acumular trabajo concurrente y aumentar presión sobre red, memoria o servicios remotos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="switchmap-cancelar-lo-anterior-y-conservar-lo-más-reciente"&gt;&lt;code&gt;switchMap&lt;/code&gt;: cancelar lo anterior y conservar lo más reciente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;switchMap&lt;/code&gt; también transforma cada emisión en un observable interno, pero mantiene activa solo la suscripción más reciente. Cuando llega una nueva emisión desde el observable fuente, cancela la suscripción interna anterior y se cambia al nuevo observable.&lt;/p&gt;
&lt;p&gt;Esta semántica es ideal para escenarios donde el resultado anterior pierde relevancia al aparecer una entrada más nueva. El caso clásico es un typeahead o autocomplete: si el usuario escribe &lt;code&gt;rea&lt;/code&gt; y luego &lt;code&gt;react&lt;/code&gt;, la respuesta de &lt;code&gt;rea&lt;/code&gt; ya no debe actualizar la UI aunque llegue después.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-switchmap_hu_113998a3529e5491.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;} &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SearchResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;id&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;title&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;term&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;length&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;([])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;getJSON&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;SearchResult&lt;/span&gt;[]&amp;gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;results&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Resultados vigentes:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;results&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El valor operativo de &lt;code&gt;switchMap&lt;/code&gt; está en la cancelación. En Angular, por ejemplo, cancelar la suscripción a una petición HTTP puede abortar la solicitud subyacente; en otros contextos, al menos evita que respuestas obsoletas lleguen al consumidor final.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Elige &lt;code&gt;switchMap&lt;/code&gt; cuando el sistema debe representar el estado más reciente: búsquedas, filtros dinámicos, navegación dependiente de parámetros o recarga de datos por selección activa.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concatmap-preservar-orden-y-ejecutar-de-forma-secuencial"&gt;&lt;code&gt;concatMap&lt;/code&gt;: preservar orden y ejecutar de forma secuencial&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;concatMap&lt;/code&gt; transforma cada emisión en un observable interno, pero no se suscribe al siguiente hasta que el observable interno actual completa. En lugar de mezclar resultados, crea una cola: procesa una tarea, espera su finalización y continúa con la siguiente.&lt;/p&gt;
&lt;p&gt;Este comportamiento es crucial cuando el orden importa o cuando el backend espera operaciones serializadas. Casos típicos incluyen guardar cambios en secuencia, ejecutar comandos de dominio, procesar pasos de onboarding o enviar eventos que deben respetar causalidad.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-concatmap_hu_6f93690790aa1f0e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;concatMap&lt;/span&gt;, &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;OrderCommand&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;validated&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;charged&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;confirmed&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;commands&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;OrderCommand&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;validated&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;charged&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;confirmed&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;commands&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;concatMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;command&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;/api/orders/commands&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;command&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Comando procesado en orden&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La principal ventaja de &lt;code&gt;concatMap&lt;/code&gt; es la predictibilidad. La desventaja es la latencia acumulada: si cada operación tarda 500 ms y tienes diez elementos, el flujo tardará al menos cinco segundos en procesar la cola completa.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;concatMap&lt;/code&gt; puede acumular una cola grande si la fuente emite más rápido de lo que completan los observables internos. Evalúa backpressure, límites de entrada o estrategias de descarte si el volumen no está controlado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="exhaustmap-ignorar-nuevas-emisiones-mientras-hay-trabajo-activo"&gt;&lt;code&gt;exhaustMap&lt;/code&gt;: ignorar nuevas emisiones mientras hay trabajo activo&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;exhaustMap&lt;/code&gt; transforma una emisión en un observable interno y, mientras ese observable está activo, ignora todas las emisiones posteriores del observable fuente. Cuando el observable interno completa, el operador queda listo para aceptar una nueva emisión.&lt;/p&gt;
&lt;p&gt;Este patrón es útil cuando una operación no debe ejecutarse dos veces en paralelo. Formularios de login, botones de pago, acciones de envío y procesos idempotentes costosos suelen beneficiarse de esta semántica: el primer evento inicia el trabajo y los siguientes clics se descartan hasta terminar.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/transformation-operators/marble-exhaustmap_hu_b8ae1a19035b9470.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;exhaustMap&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/ajax&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;PaymentResult&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;transactionId&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;payButton&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLButtonElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#pay&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;payload&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;orderId&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;A-100&amp;#39;&lt;/span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;payButton&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;exhaustMap&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;ajax&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;post&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PaymentResult&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;/api/payments&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;payload&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Pago procesado:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;response&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;transactionId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A diferencia de &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;exhaustMap&lt;/code&gt; no cancela el trabajo activo. A diferencia de &lt;code&gt;mergeMap&lt;/code&gt;, tampoco crea trabajo adicional. Su contrato es deliberadamente estricto: “ignorar mientras esté ocupado”.&lt;/p&gt;
&lt;h2 id="cuándo-elegir-cada-operador-de-transformación-rxjs"&gt;Cuándo elegir cada operador de transformación RxJS&lt;/h2&gt;
&lt;p&gt;La elección correcta depende de la política de concurrencia que necesita el sistema, no solo de la forma del código.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Usa &lt;code&gt;mergeAll&lt;/code&gt; cuando recibes observables internos ya creados y quieres mezclarlos.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;mergeMap&lt;/code&gt; cuando cada emisión dispara trabajo independiente y aceptas concurrencia.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;switchMap&lt;/code&gt; cuando solo importa el resultado más reciente y conviene cancelar lo anterior.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;concatMap&lt;/code&gt; cuando necesitas orden, serialización o consistencia secuencial.&lt;/li&gt;
&lt;li&gt;Usa &lt;code&gt;exhaustMap&lt;/code&gt; cuando una operación activa debe bloquear nuevas emisiones hasta completar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Una regla práctica es observar qué debería ocurrir si llegan tres emisiones rápidas. Si las tres deben ejecutarse, &lt;code&gt;mergeMap&lt;/code&gt;. Si solo la última importa, &lt;code&gt;switchMap&lt;/code&gt;. Si las tres deben ejecutarse en orden, &lt;code&gt;concatMap&lt;/code&gt;. Si solo la primera debe ejecutarse y las demás deben ignorarse mientras está activa, &lt;code&gt;exhaustMap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores de transformación RxJS definen cómo se conectan eventos de alto nivel con trabajo asíncrono real. &lt;code&gt;mergeAll&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;concatMap&lt;/code&gt; y &lt;code&gt;exhaustMap&lt;/code&gt; no son variantes intercambiables; cada uno codifica una política distinta de concurrencia, cancelación y orden.&lt;/p&gt;
&lt;p&gt;Al diseñar flujos reactivos en TypeScript, conviene elegir el operador a partir del contrato del dominio. Esa decisión reduce condiciones de carrera, evita respuestas obsoletas, controla presión sobre recursos externos y hace que la intención del flujo sea explícita para el equipo.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores de tiempo</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-de-tiempo-rxjs/</link><pubDate>Wed, 03 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-de-tiempo-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores de tiempo RxJS como debounceTime, throttleTime, sampleTime, sample y auditTime para controlar emisiones en streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/time-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-usar-operadores-de-tiempo-rxjs"&gt;Por qué usar operadores de tiempo RxJS&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#debouncetime-esperar-silencio-antes-de-emitir"&gt;&lt;code&gt;debounceTime&lt;/code&gt;: esperar silencio antes de emitir&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#throttletime-limitar-la-frecuencia-de-emisión"&gt;&lt;code&gt;throttleTime&lt;/code&gt;: limitar la frecuencia de emisión&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configuración-leading-y-trailing"&gt;Configuración &lt;code&gt;leading&lt;/code&gt; y &lt;code&gt;trailing&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#sampletime-tomar-snapshots-periódicos-del-último-valor"&gt;&lt;code&gt;sampleTime&lt;/code&gt;: tomar snapshots periódicos del último valor&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#sample-emitir-cuando-otro-observable-lo-indique"&gt;&lt;code&gt;sample&lt;/code&gt;: emitir cuando otro observable lo indique&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#audittime-emitir-el-último-valor-al-cerrar-una-ventana"&gt;&lt;code&gt;auditTime&lt;/code&gt;: emitir el último valor al cerrar una ventana&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#comparación-rápida-de-operadores-de-tiempo"&gt;Comparación rápida de operadores de tiempo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un flujo de eventos del navegador emite con demasiada frecuencia, la lógica de aplicación puede terminar procesando ruido en lugar de señales útiles. Los &lt;strong&gt;operadores de tiempo RxJS&lt;/strong&gt; permiten controlar esa presión temporal en escenarios como búsquedas con autocompletado, eventos de &lt;code&gt;scroll&lt;/code&gt;, clics repetidos, métricas periódicas o capturas de estado. En este artículo analizaremos &lt;code&gt;debounceTime&lt;/code&gt;, &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;sampleTime&lt;/code&gt;, &lt;code&gt;sample&lt;/code&gt; y &lt;code&gt;auditTime&lt;/code&gt; con ejemplos en TypeScript y diagramas de canicas.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de &lt;a href="https://blog.dacadev.com/typescript/operadores-basicos-rxjs/"



 


&gt;Operadores básicos&lt;/a&gt; y continuaremos con &lt;a href="https://blog.dacadev.com/typescript/operadores-de-transformacion-rxjs/"



 


&gt;Operadores de transformación&lt;/a&gt;. Aquí abordaremos cómo regular emisiones en el tiempo sin acoplar la lógica de negocio a temporizadores manuales.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-usar-operadores-de-tiempo-rxjs"&gt;Por qué usar operadores de tiempo RxJS&lt;/h2&gt;
&lt;p&gt;En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, un &lt;strong&gt;observable&lt;/strong&gt; puede emitir valores con una cadencia muy superior a la capacidad real de procesamiento de la interfaz o del backend. Un &lt;code&gt;keyup&lt;/code&gt; puede dispararse en cada tecla, un &lt;code&gt;mousemove&lt;/code&gt; puede emitir decenas de veces por segundo y un botón puede recibir clics duplicados antes de que termine una operación asíncrona. Sin control temporal, el sistema incrementa latencia, consumo de CPU y llamadas innecesarias.&lt;/p&gt;
&lt;p&gt;Los operadores de tiempo resuelven este problema dentro del pipeline reactivo. En lugar de mezclar &lt;code&gt;setTimeout&lt;/code&gt;, flags mutables y cancelaciones manuales, expresamos la política de emisión con operadores declarativos. Esto mantiene la suscripción enfocada en consumir valores ya estabilizados, muestreados o limitados.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;En ReactiveX, estos operadores suelen representarse con diagramas de canicas porque el comportamiento depende tanto del valor como del instante de emisión. Los diagramas del artículo provienen de la nota original y se conservan como referencia visual.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="debouncetime-esperar-silencio-antes-de-emitir"&gt;&lt;code&gt;debounceTime&lt;/code&gt;: esperar silencio antes de emitir&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;debounceTime&lt;/code&gt; emite el último valor del observable fuente solo cuando transcurre un intervalo sin nuevas emisiones. Si llega otro valor antes de que venza el temporizador, el valor anterior se descarta y el conteo vuelve a empezar. Esta semántica es especialmente útil para entradas de texto, filtros de búsqueda y eventos donde interesa la intención final del usuario, no cada evento intermedio.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-debouncetime_hu_df49dfb632f6cdd2.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Consideremos un flujo de clics. La suscripción recibirá un evento únicamente si pasan tres segundos sin otro clic adicional:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En formularios, &lt;code&gt;debounceTime&lt;/code&gt; suele combinarse con &lt;code&gt;distinctUntilChanged&lt;/code&gt; para evitar trabajo duplicado cuando el valor estabilizado no cambió realmente. La nota original usa &lt;code&gt;pluck('target', 'value')&lt;/code&gt;; funciona como referencia histórica, pero &lt;code&gt;pluck&lt;/code&gt; está deprecado en RxJS 7. La alternativa moderna es &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;pluck&lt;/code&gt; aparece en muchos ejemplos clásicos de RxJS, pero está deprecado. Para código nuevo, usa &lt;code&gt;map&lt;/code&gt; y extrae explícitamente la propiedad requerida; el resultado es más tipado y más claro para TypeScript.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="throttletime-limitar-la-frecuencia-de-emisión"&gt;&lt;code&gt;throttleTime&lt;/code&gt;: limitar la frecuencia de emisión&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;throttleTime&lt;/code&gt; permite emitir un valor y luego ignorar nuevas emisiones durante una ventana temporal. Por defecto, emite el primer valor de cada ventana y descarta los valores posteriores hasta que el intervalo termina. Es una estrategia útil cuando necesitas una respuesta inmediata, pero quieres proteger el sistema contra ráfagas de eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-throttletime_hu_c578b31ad733fd0c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El siguiente ejemplo procesa como máximo un valor de teclado cada &lt;code&gt;1500&lt;/code&gt; milisegundos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="configuración-leading-y-trailing"&gt;Configuración &lt;code&gt;leading&lt;/code&gt; y &lt;code&gt;trailing&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;La configuración avanzada de &lt;code&gt;throttleTime&lt;/code&gt; permite decidir si se emite el valor inicial de la ventana (&lt;code&gt;leading&lt;/code&gt;) y/o el último valor capturado durante esa ventana (&lt;code&gt;trailing&lt;/code&gt;). Esta configuración es importante cuando necesitas respuesta inmediata y, además, preservar el estado final de una ráfaga.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;createElement&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;body&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;appendChild&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;input$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;input&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;input$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;throttleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1500&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;leading&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;trailing&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/console-throttletime-leading-trailing_hu_cf13178f161f0ddf.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Con &lt;code&gt;leading: true&lt;/code&gt;, la primera emisión sale de inmediato. Con &lt;code&gt;trailing: true&lt;/code&gt;, el último valor observado durante la ventana se emite al cerrar el intervalo. Esta combinación es adecuada para interacciones donde importa tanto la reacción inicial como el estado final.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa &lt;code&gt;debounceTime&lt;/code&gt; cuando solo importa el valor estabilizado. Usa &lt;code&gt;throttleTime&lt;/code&gt; cuando necesitas una primera respuesta rápida y una frecuencia máxima controlada.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="sampletime-tomar-snapshots-periódicos-del-último-valor"&gt;&lt;code&gt;sampleTime&lt;/code&gt;: tomar snapshots periódicos del último valor&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sampleTime&lt;/code&gt; toma una muestra del último valor emitido por la fuente cada cierto intervalo. A diferencia de &lt;code&gt;throttleTime&lt;/code&gt;, el reloj no se inicia por una emisión del observable fuente; el operador usa un intervalo periódico. Si no hubo valores nuevos desde el último tick, no emite nada.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-sampletime_hu_69fc070df878c35.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El siguiente pipeline captura la última posición de clic cada dos segundos, siempre que haya ocurrido al menos un clic durante ese periodo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;sampleTime&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sampleTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Esta estrategia encaja bien en telemetría, dashboards o cálculos de posición donde no necesitas procesar cada evento, sino observar el estado más reciente a una cadencia fija. También reduce el acoplamiento entre la frecuencia de entrada y la frecuencia de procesamiento.&lt;/p&gt;
&lt;h2 id="sample-emitir-cuando-otro-observable-lo-indique"&gt;&lt;code&gt;sample&lt;/code&gt;: emitir cuando otro observable lo indique&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sample&lt;/code&gt; generaliza la idea de muestreo: en lugar de usar un intervalo fijo, recibe un observable notificador. Cada vez que el notificador emite, &lt;code&gt;sample&lt;/code&gt; publica el último valor conocido de la fuente, si existe uno disponible desde la muestra anterior.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-sample_hu_aa6f1456817a5273.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo, &lt;code&gt;interval$&lt;/code&gt; genera valores cada &lt;code&gt;500&lt;/code&gt; milisegundos, pero solo se emite el último valor cuando ocurre un clic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;sample&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;sample&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sample&lt;/code&gt; es útil cuando un evento externo define el momento de lectura. Por ejemplo, puedes mantener un stream de estado interno y emitir snapshots solo cuando el usuario confirma una acción, cuando llega una señal de sincronización o cuando otro subsistema solicita una captura.&lt;/p&gt;
&lt;h2 id="audittime-emitir-el-último-valor-al-cerrar-una-ventana"&gt;&lt;code&gt;auditTime&lt;/code&gt;: emitir el último valor al cerrar una ventana&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;auditTime&lt;/code&gt; inicia una ventana temporal cuando recibe una emisión de la fuente. Durante esa ventana ignora las emisiones intermedias, pero conserva la última. Al finalizar el intervalo, emite ese último valor capturado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/marble-audittime_hu_4ee11ac40f69d025.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Su comportamiento resulta útil cuando el primer valor de una ráfaga no es tan relevante como el valor final dentro de una ventana de procesamiento. El siguiente ejemplo registra cada clic con &lt;code&gt;tap&lt;/code&gt;, transforma la posición y luego deja pasar el último valor cada dos segundos desde el inicio de cada ventana:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;auditTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;click$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;click$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; ({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; })),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;auditTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/time-operators/console-audittime_hu_24178ca659502169.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia práctica frente a &lt;code&gt;debounceTime&lt;/code&gt; es que &lt;code&gt;auditTime&lt;/code&gt; no espera silencio global para emitir. Si hay una ráfaga continua, seguirá emitiendo el último valor de cada ventana auditada. Frente a &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;auditTime&lt;/code&gt; se enfoca en el valor final de la ventana, no en el inicial.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;auditTime&lt;/code&gt; es una buena opción para flujos de alta frecuencia donde necesitas snapshots finales por ventana: movimientos de puntero, scroll, reflujo visual o mediciones periódicas derivadas de eventos continuos.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="comparación-rápida-de-operadores-de-tiempo"&gt;Comparación rápida de operadores de tiempo&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Operador&lt;/th&gt;
 &lt;th&gt;Cuándo emite&lt;/th&gt;
 &lt;th&gt;Caso típico&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;debounceTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Cuando pasa un intervalo sin nuevas emisiones&lt;/td&gt;
 &lt;td&gt;Búsqueda después de que el usuario deja de escribir&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;throttleTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Al inicio de una ventana; opcionalmente también al final&lt;/td&gt;
 &lt;td&gt;Clics, scroll o resize con respuesta inmediata&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sampleTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;En ticks periódicos, si hay un valor nuevo&lt;/td&gt;
 &lt;td&gt;Telemetría o snapshots a cadencia fija&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;sample&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Cuando emite otro observable notificador&lt;/td&gt;
 &lt;td&gt;Capturar estado bajo demanda&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;auditTime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Al final de una ventana iniciada por la fuente&lt;/td&gt;
 &lt;td&gt;Emitir el último valor de una ráfaga temporal&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores de tiempo RxJS permiten diseñar pipelines reactivos con políticas temporales explícitas. &lt;code&gt;debounceTime&lt;/code&gt; reduce ruido esperando estabilidad, &lt;code&gt;throttleTime&lt;/code&gt; limita frecuencia con respuesta inicial, &lt;code&gt;sampleTime&lt;/code&gt; toma snapshots periódicos, &lt;code&gt;sample&lt;/code&gt; delega el momento de lectura a otro observable y &lt;code&gt;auditTime&lt;/code&gt; conserva el último valor de una ventana.&lt;/p&gt;
&lt;p&gt;Elegir correctamente entre estos operadores evita temporizadores manuales, reduce estado mutable y mantiene el control de emisiones cerca del flujo que lo necesita. En el siguiente artículo de la serie abordaremos operadores de transformación para modificar la forma de los valores que viajan por el stream.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Operadores básicos</title><link>https://blog.dacadev.com/typescript/rxjs/operadores-basicos-rxjs/</link><pubDate>Mon, 01 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/operadores-basicos-rxjs/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende operadores rxjs esenciales como map, filter, tap, reduce y scan, y domina el operador pipe rxjs para transformar streams.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-son-los-operadores-rxjs-y-cómo-funciona-pipe"&gt;Qué son los operadores rxjs y cómo funciona &lt;code&gt;pipe&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#map-transformar-emisiones-con-map-filter-rxjs"&gt;&lt;code&gt;map&lt;/code&gt;: transformar emisiones con &lt;code&gt;map filter rxjs&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#pluck-extraer-propiedades-anidadas"&gt;&lt;code&gt;pluck&lt;/code&gt;: extraer propiedades anidadas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#mapto-reemplazar-cada-emisión-por-un-valor-constante"&gt;&lt;code&gt;mapTo&lt;/code&gt;: reemplazar cada emisión por un valor constante&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#filter-filtrar-emisiones-del-stream"&gt;&lt;code&gt;filter&lt;/code&gt;: filtrar emisiones del stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#encadenamiento-con-el-operador-pipe-rxjs"&gt;Encadenamiento con el operador pipe rxjs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#tap-efectos-secundarios-sin-transformar-el-flujo"&gt;&lt;code&gt;tap&lt;/code&gt;: efectos secundarios sin transformar el flujo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#reduce-acumular-y-emitir-al-completar"&gt;&lt;code&gt;reduce&lt;/code&gt;: acumular y emitir al completar&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#scan-acumular-y-emitir-cada-estado-intermedio"&gt;&lt;code&gt;scan&lt;/code&gt;: acumular y emitir cada estado intermedio&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En una aplicación reactiva, el problema rara vez consiste solo en recibir eventos; el reto aparece al transformar, filtrar y acumular emisiones sin acoplar la lógica de negocio a cada suscripción. Los &lt;strong&gt;operadores rxjs&lt;/strong&gt; resuelven ese punto al permitir que un &lt;code&gt;Observable&lt;/code&gt; exponga un flujo derivado, más específico y más seguro para quien lo consume.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;Funciones para crear Observables&lt;/a&gt; y aquí abordaremos &lt;code&gt;pipe&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;pluck&lt;/code&gt;, &lt;code&gt;mapTo&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, encadenamiento, &lt;code&gt;tap&lt;/code&gt;, &lt;code&gt;reduce&lt;/code&gt; y &lt;code&gt;scan&lt;/code&gt;. El siguiente paso será estudiar &lt;a href="https://blog.dacadev.com/typescript/operadores-de-tiempo-rxjs/"



 


&gt;Operadores de tiempo&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="qué-son-los-operadores-rxjs-y-cómo-funciona-pipe"&gt;Qué son los operadores rxjs y cómo funciona &lt;code&gt;pipe&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;operador&lt;/strong&gt; es una función que recibe las emisiones de un &lt;code&gt;Observable&lt;/code&gt; y devuelve otro &lt;code&gt;Observable&lt;/code&gt; con un comportamiento derivado. Ese comportamiento puede transformar valores, filtrar emisiones, ejecutar efectos secundarios controlados o acumular estado a lo largo del stream.&lt;/p&gt;
&lt;p&gt;En RxJS, los operadores se aplican con el método &lt;code&gt;pipe&lt;/code&gt;. Esta API permite declarar una cadena de procesamiento explícita, donde cada operador recibe la salida del anterior y entrega su resultado al siguiente. La documentación oficial de &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt; describe este patrón como la base para componer flujos asincrónicos de manera declarativa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La suscripción no debería cargar con toda la lógica de transformación. En un diseño mantenible, &lt;code&gt;subscribe&lt;/code&gt; se reserva para consumir el resultado final, mientras que &lt;code&gt;pipe&lt;/code&gt; documenta la estrategia de procesamiento del flujo.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mantén la lógica de transformación dentro de &lt;code&gt;pipe&lt;/code&gt;. Esto reduce acoplamiento, facilita pruebas unitarias sobre operadores y evita suscripciones con demasiada responsabilidad.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="map-transformar-emisiones-con-map-filter-rxjs"&gt;&lt;code&gt;map&lt;/code&gt;: transformar emisiones con &lt;code&gt;map filter rxjs&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;map&lt;/code&gt;&lt;/strong&gt; proyecta cada emisión del &lt;code&gt;Observable&lt;/code&gt; original hacia un nuevo valor. Es equivalente al concepto de proyección funcional: por cada entrada existe una salida, sin modificar el origen y sin alterar la cantidad de emisiones.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-map_hu_e00f6d1ff71d0bd5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En el diagrama de canicas, cada valor emitido pasa por una función de transformación y continúa en el stream resultante con una nueva representación. Esto permite convertir modelos, normalizar datos o derivar valores calculados antes de que lleguen a la suscripción.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;multiplied$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;source&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;multiplied$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;map&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;También puedes escribirlo de forma compacta cuando no necesitas conservar una referencia al &lt;code&gt;Observable&lt;/code&gt; intermedio:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El resultado conserva el orden de las emisiones y aplica la función a cada valor individual.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-map_hu_e21585c67d7ecd41.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;map&lt;/code&gt; es una pieza central en pipelines donde necesitas convertir eventos del DOM, respuestas HTTP o estructuras de dominio en datos listos para la capa que los consume.&lt;/p&gt;
&lt;h2 id="pluck-extraer-propiedades-anidadas"&gt;&lt;code&gt;pluck&lt;/code&gt;: extraer propiedades anidadas&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;pluck&lt;/code&gt;&lt;/strong&gt; extrae propiedades de objetos emitidos por un &lt;code&gt;Observable&lt;/code&gt;. En notas y proyectos con RxJS más antiguos aparece con frecuencia para leer rutas como &lt;code&gt;target.baseURI&lt;/code&gt; dentro de un evento del DOM.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-pluck_hu_5426da1479087d60.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Un ejemplo clásico consiste en escuchar eventos &lt;code&gt;keyup&lt;/code&gt; y extraer una propiedad anidada del objeto &lt;code&gt;KeyboardEvent&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;pluck&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;target&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;baseURI&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;pluck&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al presionar una tecla, el &lt;code&gt;Observable&lt;/code&gt; original emite el evento completo, mientras que el stream derivado emite solo la propiedad seleccionada.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-pluck_hu_3b2445a8681576fe.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;pluck&lt;/code&gt; está deprecado en versiones modernas de RxJS. Prefiere &lt;code&gt;map&lt;/code&gt; con acceso explícito a propiedades, porque ofrece mejor tipado, autocompletado y refactorización segura.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La alternativa recomendada usa &lt;code&gt;map&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;instanceof&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Element&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;?&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;baseURI&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;baseUri$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;baseURI&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="mapto-reemplazar-cada-emisión-por-un-valor-constante"&gt;&lt;code&gt;mapTo&lt;/code&gt;: reemplazar cada emisión por un valor constante&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;mapTo&lt;/code&gt;&lt;/strong&gt; transforma cualquier entrada en un valor constante. Es útil cuando el contenido de la emisión original no importa y solo necesitas representar una señal semántica, por ejemplo: “hubo interacción”, “se presionó una tecla” o “se completó un paso”.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-map-to_hu_8f3f642b0c00aa40.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyPressed$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyup$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mapTo&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Tecla presionada&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyPressed$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mapTo&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cada evento &lt;code&gt;keyup&lt;/code&gt; se reemplaza por la misma cadena.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-map-to_hu_cbac4f701b02c8cc.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En código moderno, también puedes usar &lt;code&gt;map(() =&amp;gt; valor)&lt;/code&gt; para lograr el mismo resultado y mantener consistencia con el resto de tus transformaciones.&lt;/p&gt;
&lt;h2 id="filter-filtrar-emisiones-del-stream"&gt;&lt;code&gt;filter&lt;/code&gt;: filtrar emisiones del stream&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;filter&lt;/code&gt;&lt;/strong&gt; deja pasar únicamente las emisiones que cumplen un predicado. A diferencia de &lt;code&gt;map&lt;/code&gt;, este operador sí puede cambiar la cantidad de emisiones que recibe la suscripción, porque descarta los valores que no satisfacen la condición.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-filter_hu_1050d12e416827c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El callback de &lt;code&gt;filter&lt;/code&gt; recibe el valor emitido y el índice de la emisión. Esto permite aplicar reglas basadas en el contenido del valor o en su posición dentro del stream.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;20&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;index&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;index&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;%&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este caso, solo pasan los números impares.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-filter-numbers_hu_2e6f024c6af9ed48.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; también es útil con objetos de dominio. El siguiente ejemplo convierte un arreglo en un &lt;code&gt;Observable&lt;/code&gt; y deja pasar únicamente los personajes de tipo &lt;code&gt;heroe&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Batman&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Robin&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Joker&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;filter&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El stream resultante contiene solo los objetos que cumplen el predicado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-filter-objects_hu_33a3b6d187cd0d2a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;filter&lt;/code&gt; no transforma el valor; controla si una emisión continúa o se descarta. Si necesitas modificar el valor después del filtrado, encadena un &lt;code&gt;map&lt;/code&gt; a continuación.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="encadenamiento-con-el-operador-pipe-rxjs"&gt;Encadenamiento con el operador pipe rxjs&lt;/h2&gt;
&lt;p&gt;El &lt;strong&gt;operador pipe rxjs&lt;/strong&gt; permite componer varios operadores en una secuencia legible. Cada paso debería tener una responsabilidad clara: extraer un dato, filtrar una condición, transformar un modelo o ejecutar un efecto secundario controlado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;enterKey$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;code&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Enter&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;enterKey$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;chain&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;keyCode&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí el primer operador transforma &lt;code&gt;KeyboardEvent&lt;/code&gt; en &lt;code&gt;event.code&lt;/code&gt;, y el segundo operador deja pasar únicamente la tecla &lt;code&gt;Enter&lt;/code&gt;. La suscripción recibe un stream ya procesado, sin conocer el detalle del evento original del DOM.&lt;/p&gt;
&lt;p&gt;Esta composición es especialmente importante cuando el flujo crece. En lugar de acumular lógica imperativa dentro de callbacks, puedes expresar el pipeline de datos como una serie de transformaciones pequeñas y verificables.&lt;/p&gt;
&lt;h2 id="tap-efectos-secundarios-sin-transformar-el-flujo"&gt;&lt;code&gt;tap&lt;/code&gt;: efectos secundarios sin transformar el flujo&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;tap&lt;/code&gt;&lt;/strong&gt; ejecuta efectos secundarios sobre las emisiones, pero no modifica el valor que atraviesa el pipeline. Es una herramienta frecuente para depuración, métricas, logging o integración con observabilidad, siempre que no se use para alterar estado crítico de forma opaca.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-tap_hu_ca400b88414de95b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;numbers$&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap-antes&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;tap-despues&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;se terminó todo&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tap&lt;/code&gt; acepta un callback para &lt;code&gt;next&lt;/code&gt; o un objeto con handlers como &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;. En ambos casos, el valor que continúa hacia el siguiente operador permanece intacto.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-tap_hu_1fd193b2a444489d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Evita usar &lt;code&gt;tap&lt;/code&gt; como sustituto de &lt;code&gt;map&lt;/code&gt; o &lt;code&gt;filter&lt;/code&gt;. Si un paso cambia el valor del stream, debe expresarse con un operador de transformación explícito.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="reduce-acumular-y-emitir-al-completar"&gt;&lt;code&gt;reduce&lt;/code&gt;: acumular y emitir al completar&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt; aplica una función acumuladora sobre las emisiones y entrega un único resultado cuando el &lt;code&gt;Observable&lt;/code&gt; completa. Su comportamiento es apropiado para streams finitos, como arreglos, rangos o secuencias delimitadas con operadores como &lt;code&gt;take&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-reduce_hu_c634ff5213a00ec4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;totalReducer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;500&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;take&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;6&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tap&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalReducer&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El segundo argumento de &lt;code&gt;reduce&lt;/code&gt; define el valor inicial del acumulador. En el ejemplo, el acumulador inicia en &lt;code&gt;5&lt;/code&gt;, procesa seis emisiones del &lt;code&gt;interval&lt;/code&gt; y emite el total solo cuando &lt;code&gt;take(6)&lt;/code&gt; completa el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-reduce_hu_a2831c73d34ffa4b.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;reduce&lt;/code&gt; necesita que el &lt;code&gt;Observable&lt;/code&gt; complete para emitir el resultado. En streams infinitos o de larga vida, como eventos del DOM sin delimitador, no recibirás salida si no aplicas un operador que cierre la secuencia.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="scan-acumular-y-emitir-cada-estado-intermedio"&gt;&lt;code&gt;scan&lt;/code&gt;: acumular y emitir cada estado intermedio&lt;/h2&gt;
&lt;p&gt;El operador &lt;strong&gt;&lt;code&gt;scan&lt;/code&gt;&lt;/strong&gt; también aplica una función acumuladora, pero emite cada estado intermedio del acumulador. Esta diferencia lo convierte en una pieza clave para modelar estado reactivo: contadores, historial de acciones, progreso incremental o snapshots derivados de eventos.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/marble-scan_hu_104ac87779ead247.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Comparar &lt;code&gt;reduce&lt;/code&gt; y &lt;code&gt;scan&lt;/code&gt; sobre la misma secuencia deja clara la diferencia operativa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;accumulator&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;current&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;reduce&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;reduce&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numbers&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;totalAccumulator&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;scan&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;reduce&lt;/code&gt; emite solo el total final. &lt;code&gt;scan&lt;/code&gt; emite &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;6&lt;/code&gt;, &lt;code&gt;10&lt;/code&gt; y &lt;code&gt;15&lt;/code&gt;, porque cada emisión representa el nuevo estado acumulado.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/basic-operators/console-reduce-scan_hu_9b17532d32728e9f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En arquitecturas reactivas, &lt;code&gt;scan&lt;/code&gt; suele ser más útil que &lt;code&gt;reduce&lt;/code&gt; cuando el consumidor necesita reaccionar a cada transición de estado, no solo al resultado final.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los operadores básicos de RxJS permiten convertir streams genéricos en flujos especializados y mantenibles. &lt;code&gt;map&lt;/code&gt; transforma, &lt;code&gt;filter&lt;/code&gt; controla qué continúa, &lt;code&gt;tap&lt;/code&gt; observa sin modificar, &lt;code&gt;reduce&lt;/code&gt; acumula hasta completar y &lt;code&gt;scan&lt;/code&gt; expone cada estado acumulado.&lt;/p&gt;
&lt;p&gt;Dominar &lt;code&gt;pipe&lt;/code&gt; y estos operadores establece una base sólida para operadores más avanzados. En el siguiente artículo de la serie abordaremos operadores de tiempo, donde la latencia, la frecuencia de emisión y la coordinación temporal pasan a ser parte central del diseño reactivo.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Funciones para crear Observables</title><link>https://blog.dacadev.com/typescript/rxjs/funciones-crear-observables/</link><pubDate>Sat, 30 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/funciones-crear-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende a crear observables RxJS con of, from, fromEvent, range, interval, timer y asyncScheduler en flujos síncronos y asíncronos.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#crear-observables-rxjs-con-funciones-de-creación"&gt;Crear observables RxJS con funciones de creación&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#of-emitir-cada-argumento-como-un-valor-independiente"&gt;&lt;code&gt;of&lt;/code&gt;: emitir cada argumento como un valor independiente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#from-convertir-iterables-arreglos-y-promesas-en-observables"&gt;&lt;code&gt;from&lt;/code&gt;: convertir iterables, arreglos y promesas en Observables&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#fromevent-crear-observables-desde-eventos-del-dom"&gt;&lt;code&gt;fromEvent&lt;/code&gt;: crear Observables desde eventos del DOM&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#identificar-el-tipo-del-evento-sin-usar-any"&gt;Identificar el tipo del evento sin usar &lt;code&gt;any&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#range-generar-secuencias-numéricas"&gt;&lt;code&gt;range&lt;/code&gt;: generar secuencias numéricas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#rangecount-contar-desde-cero"&gt;&lt;code&gt;range(count)&lt;/code&gt;: contar desde cero&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rangestart-count-definir-inicio-y-cantidad"&gt;&lt;code&gt;range(start, count)&lt;/code&gt;: definir inicio y cantidad&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#rangestart-count-asyncscheduler-diferir-la-ejecución"&gt;&lt;code&gt;range(start, count, asyncScheduler)&lt;/code&gt;: diferir la ejecución&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#interval-emitir-valores-periódicamente"&gt;&lt;code&gt;interval&lt;/code&gt;: emitir valores periódicamente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#timer-emitir-después-de-un-tiempo-o-iniciar-un-intervalo-diferido"&gt;&lt;code&gt;timer&lt;/code&gt;: emitir después de un tiempo o iniciar un intervalo diferido&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configuraciones-especiales-de-timer"&gt;Configuraciones especiales de &lt;code&gt;timer&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#asyncscheduler-programar-trabajo-asíncrono"&gt;&lt;code&gt;asyncScheduler&lt;/code&gt;: programar trabajo asíncrono&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#reprogramar-una-tarea-y-cancelar-la-suscripción"&gt;Reprogramar una tarea y cancelar la suscripción&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando modelamos interacciones de usuario, temporizadores, colecciones o tareas diferidas, la decisión inicial suele ser cómo &lt;strong&gt;crear observables RxJS&lt;/strong&gt; sin introducir acoplamiento innecesario ni perder claridad sobre la sincronía del flujo. En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, las funciones de creación encapsulan patrones comunes para construir &lt;strong&gt;Observables&lt;/strong&gt; a partir de valores, iterables, eventos del DOM y relojes internos.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de analizar &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt; y aquí abordaremos &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;fromEvent&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;timer&lt;/code&gt; y &lt;code&gt;asyncScheduler&lt;/code&gt;. El siguiente paso será estudiar &lt;a href="https://blog.dacadev.com/typescript/operadores-basicos-rxjs/"



 


&gt;Operadores básicos&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="crear-observables-rxjs-con-funciones-de-creación"&gt;Crear observables RxJS con funciones de creación&lt;/h2&gt;
&lt;p&gt;Las funciones de creación producen un &lt;code&gt;Observable&lt;/code&gt; sin escribir manualmente el constructor &lt;code&gt;new Observable(...)&lt;/code&gt;. Esto reduce código repetitivo y comunica la intención del stream: emitir valores estáticos, recorrer una colección, escuchar eventos o programar emisiones en el tiempo.&lt;/p&gt;
&lt;p&gt;La diferencia más importante está en la &lt;strong&gt;naturaleza síncrona o asíncrona&lt;/strong&gt; del observable resultante. &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt; y &lt;code&gt;range&lt;/code&gt; pueden emitir inmediatamente durante la suscripción. &lt;code&gt;fromEvent&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt; y &lt;code&gt;timer&lt;/code&gt;, en cambio, dependen de eventos externos o del paso del tiempo.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un observable puede ser finito o infinito. &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt; y &lt;code&gt;timer(2000)&lt;/code&gt; completan; &lt;code&gt;fromEvent&lt;/code&gt; e &lt;code&gt;interval&lt;/code&gt; no completan por sí mismos y requieren cancelar la suscripción o aplicar operadores como &lt;code&gt;take&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="of-emitir-cada-argumento-como-un-valor-independiente"&gt;&lt;code&gt;of&lt;/code&gt;: emitir cada argumento como un valor independiente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;of&lt;/code&gt; crea un observable síncrono a partir de los argumentos que recibe. Cada argumento se convierte en una emisión individual y, al terminar la lista, el stream envía &lt;code&gt;complete&lt;/code&gt;.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-of_hu_8d63db9b45300fec.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Esta característica es útil para valores estáticos, pruebas unitarias, mocks de servicios o flujos donde necesitas transformar una secuencia pequeña sin depender de una fuente externa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;string&amp;#39;&lt;/span&gt;, &lt;span style="color:#e5c07b"&gt;true&lt;/span&gt;, () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {}, &lt;span style="color:#d19a66"&gt;1.14&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio del obs$&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado!&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin del obs$&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Como &lt;code&gt;of&lt;/code&gt; es síncrono, todas las emisiones ocurren antes de ejecutar &lt;code&gt;console.log('Fin del obs$')&lt;/code&gt;. Esta propiedad es relevante cuando mezclas streams síncronos con lógica de UI o con efectos secundarios que dependen del orden de ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Si pasas un arreglo a &lt;code&gt;of&lt;/code&gt;, el arreglo completo se emite como un único valor. Si necesitas emitir cada elemento del arreglo, usa &lt;code&gt;from&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="from-convertir-iterables-arreglos-y-promesas-en-observables"&gt;&lt;code&gt;from&lt;/code&gt;: convertir iterables, arreglos y promesas en Observables&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;from&lt;/code&gt; crea un observable a partir de estructuras que ya representan una secuencia o un valor diferido: arreglos, iterables, strings, &lt;code&gt;Promise&lt;/code&gt;, entre otros. Con un arreglo, emite cada elemento de manera independiente y luego completa.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;interface&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Personaje&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;|&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Personaje&lt;/span&gt;[] &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Batman&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;heroe&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Robin&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e06c75"&gt;tipo&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;villano&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;Joker&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personajes&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;from&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;personaje&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-from_hu_631d68b1a4f8ad3c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia conceptual entre &lt;code&gt;of(personajes)&lt;/code&gt; y &lt;code&gt;from(personajes)&lt;/code&gt; es crítica. El primero emite un solo arreglo; el segundo emite tres objetos. Esa elección define el contrato del stream para los operadores posteriores.&lt;/p&gt;
&lt;h2 id="fromevent-crear-observables-desde-eventos-del-dom"&gt;&lt;code&gt;fromEvent&lt;/code&gt;: crear Observables desde eventos del DOM&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fromEvent&lt;/code&gt; convierte una fuente de eventos en un observable. Recibe el &lt;strong&gt;target&lt;/strong&gt; que expone eventos —por ejemplo &lt;code&gt;document&lt;/code&gt;, &lt;code&gt;window&lt;/code&gt; o un elemento HTML— y el nombre del evento.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-fromevent_hu_57a116438ce091e5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;clicks$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;keyups$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;KeyboardEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;keyup&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;clicks$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;click:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;keyups$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;event&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;key:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-fromevent_hu_68f1a422678c891d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este observable es infinito por defecto. El navegador seguirá emitiendo eventos mientras exista la suscripción, por lo que en componentes con ciclo de vida —por ejemplo Angular, React o Web Components— debes liberar recursos cuando el componente se desmonta.&lt;/p&gt;
&lt;h3 id="identificar-el-tipo-del-evento-sin-usar-any"&gt;Identificar el tipo del evento sin usar &lt;code&gt;any&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;En TypeScript conviene evitar &lt;code&gt;fromEvent&amp;lt;any&amp;gt;&lt;/code&gt;, porque rompe el contrato de tipos justo en la frontera del sistema. Una forma práctica de identificar el tipo consiste en inspeccionar temporalmente el evento y reemplazar &lt;code&gt;any&lt;/code&gt; por la interfaz específica.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;any&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/editor-event-type-inspection_hu_dce3b9c0b7946a91.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Al revisar el objeto emitido en consola o desde el editor, puedes identificar si corresponde a &lt;code&gt;PointerEvent&lt;/code&gt;, &lt;code&gt;KeyboardEvent&lt;/code&gt;, &lt;code&gt;MouseEvent&lt;/code&gt;, &lt;code&gt;InputEvent&lt;/code&gt; u otro tipo del DOM. Después reemplazas &lt;code&gt;any&lt;/code&gt; por el tipo correcto.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;source$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;PointerEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;source$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; }) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;({ &lt;span style="color:#e06c75"&gt;x&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;y&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/editor-event-type-applied_hu_90ad704b8eae2a21.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;fromEvent&lt;/code&gt; no completa automáticamente. En flujos de UI, combina la suscripción con &lt;code&gt;takeUntil&lt;/code&gt;, &lt;code&gt;AbortController&lt;/code&gt;, el ciclo de vida del framework o una suscripción compuesta para evitar fugas de memoria.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="range-generar-secuencias-numéricas"&gt;&lt;code&gt;range&lt;/code&gt;: generar secuencias numéricas&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;range&lt;/code&gt; crea una secuencia numérica finita. Por defecto emite de forma síncrona, lo que permite usarlo para generar índices, alimentar pruebas o construir flujos deterministas.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-range_hu_6c23fd238ca55c84.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="rangecount-contar-desde-cero"&gt;&lt;code&gt;range(count)&lt;/code&gt;: contar desde cero&lt;/h3&gt;
&lt;p&gt;Cuando recibe un solo argumento, &lt;code&gt;range&lt;/code&gt; interpreta ese valor como la cantidad de emisiones. El conteo inicia en &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-count_hu_c37fa0c5e18bfd8d.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El resultado emite &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt; y &lt;code&gt;4&lt;/code&gt;. No emite &lt;code&gt;5&lt;/code&gt;, porque el parámetro define la cantidad de valores, no el límite superior inclusivo.&lt;/p&gt;
&lt;h3 id="rangestart-count-definir-inicio-y-cantidad"&gt;&lt;code&gt;range(start, count)&lt;/code&gt;: definir inicio y cantidad&lt;/h3&gt;
&lt;p&gt;Con dos argumentos, el primero define el valor inicial y el segundo la cantidad de emisiones.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-start-count_hu_ae16b1835b3b46a9.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este stream emite &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;5&lt;/code&gt; y &lt;code&gt;6&lt;/code&gt;. El contrato sigue siendo finito y síncrono.&lt;/p&gt;
&lt;h3 id="rangestart-count-asyncscheduler-diferir-la-ejecución"&gt;&lt;code&gt;range(start, count, asyncScheduler)&lt;/code&gt;: diferir la ejecución&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; permite programar las emisiones de forma asíncrona. El cambio se observa en el orden de los &lt;code&gt;console.log&lt;/code&gt;: primero se ejecuta el código síncrono restante y luego comienzan las emisiones.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;range&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;src$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;src$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-range-asyncscheduler_hu_c450707bfca0f732.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; no convierte el trabajo en paralelismo real. Programa tareas asíncronas sobre la cola de ejecución, similar a diferir trabajo con temporizadores.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="interval-emitir-valores-periódicamente"&gt;&lt;code&gt;interval&lt;/code&gt;: emitir valores periódicamente&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;interval&lt;/code&gt; crea un observable asíncrono e infinito. Recibe un periodo en milisegundos y emite un contador incremental en cada tick.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-interval_hu_3f367558cb1b4263.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;interval$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// En una aplicación real, cancela la suscripción según el ciclo de vida.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// subscription.unsubscribe();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-interval_hu_1b82e1dcf23f03fe.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;&lt;code&gt;interval&lt;/code&gt; no emite &lt;code&gt;complete&lt;/code&gt;. Si necesitas un número limitado de emisiones, puedes combinarlo con operadores como &lt;code&gt;take&lt;/code&gt;, &lt;code&gt;takeUntil&lt;/code&gt; o &lt;code&gt;timeout&lt;/code&gt;, que analizaremos en artículos posteriores de la serie.&lt;/p&gt;
&lt;h2 id="timer-emitir-después-de-un-tiempo-o-iniciar-un-intervalo-diferido"&gt;&lt;code&gt;timer&lt;/code&gt;: emitir después de un tiempo o iniciar un intervalo diferido&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;timer&lt;/code&gt; también es asíncrono, pero su configuración inicial es distinta. Con un único parámetro numérico, espera esa cantidad de milisegundos, emite &lt;code&gt;0&lt;/code&gt; y completa.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/marble-timer_hu_c5ef5784484f6fc5.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-timer_hu_bab5418d019c3a86.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;h3 id="configuraciones-especiales-de-timer"&gt;Configuraciones especiales de &lt;code&gt;timer&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;timer&lt;/code&gt; acepta configuraciones que cubren varios casos operativos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timer(0)&lt;/code&gt; agenda la emisión tan pronto como la cola de tareas lo permita, después del trabajo síncrono actual.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timer(2000, 1000)&lt;/code&gt; espera dos segundos y luego se comporta como un intervalo que emite cada segundo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timer(fecha)&lt;/code&gt; permite agendar la primera emisión para un instante específico usando un objeto &lt;code&gt;Date&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;timer&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;timer$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;timer(2000, 1000)&lt;/code&gt; deja de ser finito. Después de la primera emisión, continúa como un intervalo y debe cancelarse cuando ya no sea necesario.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="asyncscheduler-programar-trabajo-asíncrono"&gt;&lt;code&gt;asyncScheduler&lt;/code&gt;: programar trabajo asíncrono&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncScheduler&lt;/code&gt; permite programar tareas usando la infraestructura de schedulers de RxJS. Puede reemplazar casos simples de &lt;code&gt;setTimeout&lt;/code&gt; y habilita patrones donde una tarea se reprograma a sí misma.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;hola mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-immediate_hu_d8901f49376da41c.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;También puedes definir un retraso explícito en milisegundos y pasar un único estado a la función programada.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;string&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`hola mundo, &lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e06c75"&gt;nombre&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludar&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2000&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;David&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-argument_hu_54af5b19a60430e.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Si necesitas pasar múltiples valores, usa un objeto como estado y desestructúralo en la función. Esto mantiene una firma estable y evita depender de parámetros posicionales adicionales.&lt;/p&gt;
&lt;h3 id="reprogramar-una-tarea-y-cancelar-la-suscripción"&gt;Reprogramar una tarea y cancelar la suscripción&lt;/h3&gt;
&lt;p&gt;Una acción programada puede invocar &lt;code&gt;this.schedule(...)&lt;/code&gt; para encadenar la siguiente ejecución. La suscripción resultante permite detener el ciclo.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;SchedulerAction&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Inicio&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;function&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; &lt;span style="color:#e06c75"&gt;SchedulerAction&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;state&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;number&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;state&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;state&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;this&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;state&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncScheduler&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;schedule&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Unsubscribe&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Fin&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/creation-functions/console-asyncscheduler-recursive_hu_201ae045c15be6d4.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 






 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa schedulers cuando necesites controlar explícitamente cuándo ocurre la ejecución. Para transformación de streams, normalmente conviene preferir operadores de RxJS antes que programar tareas manualmente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Las funciones de creación definen el contrato inicial del stream. &lt;code&gt;of&lt;/code&gt; emite argumentos, &lt;code&gt;from&lt;/code&gt; expande estructuras iterables o promesas, &lt;code&gt;fromEvent&lt;/code&gt; conecta eventos del DOM, &lt;code&gt;range&lt;/code&gt; genera secuencias numéricas, &lt;code&gt;interval&lt;/code&gt; modela ticks periódicos y &lt;code&gt;timer&lt;/code&gt; cubre emisiones diferidas o intervalos con retardo inicial.&lt;/p&gt;
&lt;p&gt;Dominar estas diferencias evita errores sutiles de sincronía, fugas de suscripción y contratos ambiguos entre productores y consumidores. Con esta base, el siguiente paso natural es aplicar operadores para transformar, filtrar y combinar emisiones dentro de una arquitectura reactiva mantenible.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Observables, Subscriptions y Subjects</title><link>https://blog.dacadev.com/typescript/rxjs/rxjs-observables/</link><pubDate>Thu, 28 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/rxjs-observables/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende observables rxjs con new Observable, Observer, subscribe unsubscribe, teardown y Subject para flujos multicast en TypeScript.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/observables/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#crear-observables-rxjs-con-new-observable"&gt;Crear observables rxjs con &lt;code&gt;new Observable&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-interfaz-observer-next-error-y-complete"&gt;La interfaz &lt;code&gt;Observer&lt;/code&gt;: &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subscription-y-unsubscribe-controlar-la-vida-útil-del-stream"&gt;&lt;code&gt;Subscription&lt;/code&gt; y &lt;code&gt;unsubscribe&lt;/code&gt;: controlar la vida útil del stream&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#finalizar-desde-el-observable-con-complete"&gt;Finalizar desde el observable con &lt;code&gt;complete()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#encadenar-suscripciones-con-add"&gt;Encadenar suscripciones con &lt;code&gt;.add()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subject-rxjs-multicast-y-observable-caliente"&gt;&lt;code&gt;Subject RxJS&lt;/code&gt;: multicast y observable caliente&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#emitir-y-completar-desde-un-subject"&gt;Emitir y completar desde un &lt;code&gt;Subject&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Cuando un flujo asíncrono combina eventos de usuario, timers, llamadas HTTP y actualizaciones de estado, el problema no es solo recibir datos: es modelar correctamente la vida útil de cada stream. &lt;strong&gt;Observables RxJS&lt;/strong&gt; permite representar esos flujos como secuencias cancelables, componibles y explícitas, con una semántica clara para emisión, error, finalización y limpieza de recursos.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo forma parte de la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Venimos de &lt;a href="https://blog.dacadev.com/typescript/introduccion-extensiones-reactivas/"



 


&gt;Introducción a las extensiones reactivas&lt;/a&gt; y aquí analizaremos &lt;code&gt;Observable&lt;/code&gt;, &lt;code&gt;Observer&lt;/code&gt;, &lt;code&gt;Subscription&lt;/code&gt;, &lt;code&gt;unsubscribe&lt;/code&gt;, teardown callbacks y &lt;code&gt;Subject&lt;/code&gt;. El siguiente paso será &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;Funciones para crear Observables&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="crear-observables-rxjs-con-new-observable"&gt;Crear observables rxjs con &lt;code&gt;new Observable&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;En &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;RxJS&lt;/a&gt;, un &lt;strong&gt;Observable&lt;/strong&gt; representa una fuente de valores que puede emitir cero, uno o muchos elementos a lo largo del tiempo. La forma más directa de construir uno es instanciar &lt;code&gt;Observable&lt;/code&gt; y entregar una función de suscripción. Esa función recibe un &lt;code&gt;subscriber&lt;/code&gt;, que actúa como canal para emitir valores con &lt;code&gt;next&lt;/code&gt;, reportar errores con &lt;code&gt;error&lt;/code&gt; o finalizar con &lt;code&gt;complete&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;// Después de complete(), estas emisiones ya no llegan al consumidor.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La convención del sufijo &lt;code&gt;$&lt;/code&gt; en &lt;code&gt;obs$&lt;/code&gt; no es obligatoria, pero ayuda a comunicar que una variable representa un stream. También es importante declarar el tipo del observable, por ejemplo &lt;code&gt;Observable&amp;lt;string&amp;gt;&lt;/code&gt;, porque TypeScript podrá validar el contrato entre la fuente y sus consumidores.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;complete()&lt;/code&gt; no destruye el objeto observable; cierra la ejecución de esa suscripción específica. A partir de ese punto, el consumidor ya no recibe nuevas emisiones de esa instancia de ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Modela el tipo del stream desde el inicio. Un &lt;code&gt;Observable&amp;lt;User&amp;gt;&lt;/code&gt; comunica mucho más que un &lt;code&gt;Observable&amp;lt;unknown&amp;gt;&lt;/code&gt; y reduce errores en operadores, observers y callbacks de suscripción.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="la-interfaz-observer-next-error-y-complete"&gt;La interfaz &lt;code&gt;Observer&lt;/code&gt;: &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Para consumir un observable usamos &lt;code&gt;subscribe&lt;/code&gt;. En versiones modernas de RxJS es preferible pasar un objeto compatible con la interfaz &lt;strong&gt;Observer&lt;/strong&gt;, en lugar de usar la sobrecarga antigua de tres callbacks separados.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;string&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Hola&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;mundo&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La interfaz divide explícitamente los tres canales del stream:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;next&lt;/code&gt;: se ejecuta cada vez que el observable emite un valor.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;error&lt;/code&gt;: se ejecuta cuando la fuente reporta un fallo terminal.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;complete&lt;/code&gt;: se ejecuta cuando la fuente finaliza correctamente.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt; son señales terminales. Después de cualquiera de ellas, la suscripción queda cerrada y no debe esperarse más trabajo desde esa ejecución.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Forma antigua: evita esta sobrecarga en código nuevo.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Next&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;complete&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;// Forma recomendada.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;obs$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La documentación oficial de &lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;ReactiveX&lt;/a&gt; describe este contrato como una secuencia de notificaciones donde el observable invoca al observer. RxJS conserva esa idea y la adapta al ecosistema JavaScript con cancelación explícita mediante suscripciones.&lt;/p&gt;
&lt;h2 id="subscription-y-unsubscribe-controlar-la-vida-útil-del-stream"&gt;&lt;code&gt;Subscription&lt;/code&gt; y &lt;code&gt;unsubscribe&lt;/code&gt;: controlar la vida útil del stream&lt;/h2&gt;
&lt;p&gt;Cada llamada a &lt;code&gt;subscribe&lt;/code&gt; crea una &lt;strong&gt;Subscription&lt;/strong&gt;. Esa suscripción representa la ejecución activa entre un observable y un consumidor. Si el observable administra recursos externos, como un &lt;code&gt;setInterval&lt;/code&gt;, un WebSocket o un listener del DOM, la suscripción debe liberar esos recursos cuando el consumidor ya no los necesita.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Intervalo destruido&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs1:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs2:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs3:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-intervalos_hu_44a3eabde95f1ade.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;En este ejemplo, cada suscripción recibe su propio contador porque el observable es &lt;strong&gt;cold&lt;/strong&gt;: la producción de datos ocurre dentro de la función de suscripción. Tres suscripciones implican tres ejecuciones independientes del &lt;code&gt;setInterval&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La función retornada desde el constructor del observable es el &lt;strong&gt;teardown callback&lt;/strong&gt;. RxJS la ejecuta cuando llamamos &lt;code&gt;unsubscribe()&lt;/code&gt; o cuando la suscripción se cierra por una señal terminal. Es el lugar correcto para liberar timers, conexiones, listeners o cualquier recurso asociado a esa ejecución.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;No tratar &lt;code&gt;unsubscribe()&lt;/code&gt; como un detalle opcional puede producir fugas de memoria y procesos activos innecesarios. En streams infinitos, como &lt;code&gt;interval&lt;/code&gt;, eventos del DOM o sockets, la limpieza explícita es parte del diseño.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="finalizar-desde-el-observable-con-complete"&gt;Finalizar desde el observable con &lt;code&gt;complete()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;También es posible cerrar la suscripción desde la propia fuente. Para ello, el observable invoca &lt;code&gt;subscriber.complete()&lt;/code&gt;. Cuando esto ocurre, RxJS ejecuta el callback &lt;code&gt;complete&lt;/code&gt; del observer y posteriormente ejecuta el teardown registrado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;let&lt;/span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;++&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;obs:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;contador&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;2500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Intervalo destruido&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-complete_hu_5598a64f18fe7fdf.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Aunque el &lt;code&gt;setTimeout&lt;/code&gt; final intenta cancelar las suscripciones a los seis segundos, cada una ya fue completada por el observable a los 2.5 segundos. La llamada posterior a &lt;code&gt;unsubscribe()&lt;/code&gt; no vuelve a emitir &lt;code&gt;complete&lt;/code&gt;; simplemente opera sobre una suscripción cerrada.&lt;/p&gt;
&lt;p&gt;Esta diferencia es relevante en diseño de APIs. &lt;code&gt;complete()&lt;/code&gt; comunica que la fuente terminó correctamente; &lt;code&gt;unsubscribe()&lt;/code&gt; comunica que el consumidor ya no quiere recibir valores. Ambas rutas cierran la suscripción, pero expresan intenciones distintas.&lt;/p&gt;
&lt;h2 id="encadenar-suscripciones-con-add"&gt;Encadenar suscripciones con &lt;code&gt;.add()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Cuando varias suscripciones comparten el mismo ciclo de vida, RxJS permite agruparlas con &lt;code&gt;.add()&lt;/code&gt;. Esto evita repetir llamadas a &lt;code&gt;unsubscribe()&lt;/code&gt; y centraliza la limpieza en una suscripción raíz.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalos$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;add&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subs3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Completado Timeout&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;6000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Al cancelar &lt;code&gt;subs1&lt;/code&gt;, RxJS cancela también las suscripciones agregadas. Este patrón resulta útil cuando un componente, servicio o caso de uso crea múltiples streams relacionados y necesita destruirlos como una unidad.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Agrupa suscripciones solo cuando comparten el mismo ownership. Si dos streams tienen ciclos de vida diferentes, unirlos artificialmente puede cancelar trabajo legítimo antes de tiempo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="subject-rxjs-multicast-y-observable-caliente"&gt;&lt;code&gt;Subject RxJS&lt;/code&gt;: multicast y observable caliente&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;Subject&lt;/strong&gt; combina dos roles: es un observable y también es un observer. Puede recibir valores mediante &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; o &lt;code&gt;complete&lt;/code&gt;, y al mismo tiempo permite que múltiples consumidores se suscriban a él.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;Math&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;random&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;3000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;num&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs1:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;num&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;subs2:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;num&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-subject_hu_4facf6ec81c8737f.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;La diferencia clave es que &lt;code&gt;Subject&lt;/code&gt; habilita &lt;strong&gt;multicast&lt;/strong&gt;: una sola ejecución de la fuente puede distribuir la misma emisión a varios observers. En lugar de crear un &lt;code&gt;setInterval&lt;/code&gt; por cada consumidor, el &lt;code&gt;Subject&lt;/code&gt; actúa como punto de difusión.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[Observable fuente] --&gt; B[Subject]
 B --&gt; C[Observer 1]
 B --&gt; D[Observer 2]
 B --&gt; E[Observer 3]
&lt;/pre&gt;

&lt;p&gt;En términos de hot y cold observables, un observable es &lt;strong&gt;cold&lt;/strong&gt; cuando la producción de datos ocurre dentro de la suscripción y cada consumidor obtiene su propia ejecución. Un observable es &lt;strong&gt;hot&lt;/strong&gt; cuando la producción de datos existe fuera de una suscripción individual y puede compartirse entre varios consumidores.&lt;/p&gt;
&lt;p&gt;El &lt;code&gt;Subject&lt;/code&gt; puede convertir un flujo cold en un flujo hot desde la perspectiva de los subscribers conectados al subject. La fuente se ejecuta una vez y el &lt;code&gt;Subject&lt;/code&gt; distribuye los valores a múltiples listeners.&lt;/p&gt;
&lt;h2 id="emitir-y-completar-desde-un-subject"&gt;Emitir y completar desde un &lt;code&gt;Subject&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Como &lt;code&gt;Subject&lt;/code&gt; también es un observer, puede emitir valores propios. Esto permite introducir valores manualmente en el stream, además de reenviar los valores provenientes de una fuente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Observer&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;Observer&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;siguiente&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;err&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;err&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;info&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;completado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;setInterval&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;Math&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;random&lt;/span&gt;());
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, &lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;clearInterval&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;intervalId&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;SetInterval terminado&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; };
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Subject&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;baseInterval&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;intervalo$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs1&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subs2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;observer&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;setTimeout&lt;/span&gt;(() &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subject$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;baseInterval&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#d19a66"&gt;3500&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/observables/console-output-hot_hu_d0473069b092df1a.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;El detalle operativo es importante: llamar &lt;code&gt;subject$.complete()&lt;/code&gt; cierra el subject y notifica a sus suscriptores, pero no necesariamente cancela la suscripción original que alimentaba al subject. Por eso el ejemplo ejecuta &lt;code&gt;baseInterval.unsubscribe()&lt;/code&gt; de forma explícita.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un &lt;code&gt;Subject&lt;/code&gt; concentra poder y acoplamiento. Úsalo cuando necesitas multicast o una frontera explícita entre productor y consumidores; evita convertirlo en un bus global mutable sin ownership claro.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;Los &lt;strong&gt;observables rxjs&lt;/strong&gt; ofrecen un contrato robusto para representar streams asíncronos en TypeScript. &lt;code&gt;Observer&lt;/code&gt; define cómo reaccionar ante &lt;code&gt;next&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt; y &lt;code&gt;complete&lt;/code&gt;; &lt;code&gt;Subscription&lt;/code&gt; controla la vida útil de la ejecución; &lt;code&gt;unsubscribe()&lt;/code&gt; dispara la limpieza mediante el teardown callback; y &lt;code&gt;.add()&lt;/code&gt; permite componer ciclos de vida relacionados.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Subject&lt;/code&gt; amplía el modelo al habilitar multicast y convertir flujos cold en flujos hot bajo ciertas condiciones. Esta capacidad es útil, pero exige ownership explícito: completar el subject y cancelar la fuente no siempre son la misma operación.&lt;/p&gt;
&lt;p&gt;En el siguiente artículo abordaremos las &lt;a href="https://blog.dacadev.com/typescript/funciones-crear-observables/"



 


&gt;funciones para crear Observables&lt;/a&gt;, una forma más declarativa y menos manual de construir streams con RxJS.&lt;/p&gt;</content:encoded></item><item><title>RxJs: Introducción a las extensiones reactivas</title><link>https://blog.dacadev.com/typescript/rxjs/introduccion-extensiones-reactivas/</link><pubDate>Tue, 26 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/typescript/rxjs/introduccion-extensiones-reactivas/</guid><dc:creator>Dacadev</dc:creator><category>programación</category><description>Aprende programación reactiva con RxJs, ReactiveX, Observables, Subscribers, operadores, diagramas de canicas y setup inicial.</description><media:content url="https://blog.dacadev.com/images/typescript/rxjs/intro/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#por-qué-usar-extensiones-reactivas-en-aplicaciones-web"&gt;Por qué usar extensiones reactivas en aplicaciones web&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuándo-usar-programación-reactiva-con-rxjs"&gt;Cuándo usar programación reactiva con RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#elementos-de-las-extensiones-reactivas"&gt;Elementos de las extensiones reactivas&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#observables-la-fuente-de-información"&gt;Observables: la fuente de información&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#subscribers-consumidores-del-flujo"&gt;Subscribers: consumidores del flujo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#operators-transformación-filtrado-y-composición"&gt;Operators: transformación, filtrado y composición&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#beneficios-de-rxjs-y-las-extensiones-reactivas"&gt;Beneficios de RxJs y las extensiones reactivas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#qué-es-reactivex"&gt;Qué es ReactiveX&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#patrón-observer-notificación-uno-a-muchos"&gt;Patrón Observer: notificación uno a muchos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#patrón-iterator-operaciones-secuenciales"&gt;Patrón Iterator: operaciones secuenciales&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#programación-funcional-composición-sin-mutación"&gt;Programación funcional: composición sin mutación&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#diagrama-de-canicas-en-rxjs"&gt;Diagrama de canicas en RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#configuración-del-proyecto-para-la-serie-rxjs"&gt;Configuración del proyecto para la serie RxJs&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#conclusión"&gt;Conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En aplicaciones web modernas, la &lt;strong&gt;programación reactiva&lt;/strong&gt; aparece cuando el sistema debe responder a múltiples fuentes de eventos sin bloquear la interfaz: entradas del usuario, respuestas HTTP, mensajes por WebSocket, timers, estado compartido y cambios que llegan en momentos distintos. Administrar esos flujos solo con callbacks o promesas aisladas suele aumentar el acoplamiento y dificulta expresar transformaciones, cancelaciones y composición de eventos. &lt;strong&gt;RxJs&lt;/strong&gt; aborda este problema con &lt;strong&gt;extensiones reactivas&lt;/strong&gt; basadas en flujos de datos observables.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este artículo abre la &lt;strong&gt;serie RxJs&lt;/strong&gt;. Analizaremos qué son las extensiones reactivas, qué papel cumple ReactiveX, cómo se relacionan Observables, Subscribers y Operators, cómo leer diagramas de canicas y cómo preparar el proyecto base. No hay artículo anterior; el siguiente artículo es &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="por-qué-usar-extensiones-reactivas-en-aplicaciones-web"&gt;Por qué usar extensiones reactivas en aplicaciones web&lt;/h2&gt;
&lt;p&gt;La expectativa actual de una interfaz es operar en tiempo real o casi real. Un formulario con autocompletado, un dashboard con métricas en vivo o una pantalla de trading no puede depender de recargas completas de página para reflejar cambios. La aplicación necesita reaccionar a eventos concurrentes y mantener la experiencia de usuario estable mientras ejecuta trabajo asíncrono.&lt;/p&gt;
&lt;p&gt;Las &lt;strong&gt;extensiones reactivas&lt;/strong&gt; permiten modelar esos eventos como flujos. En lugar de distribuir lógica en múltiples callbacks, representamos la fuente de datos como un &lt;code&gt;Observable&lt;/code&gt; y aplicamos operadores para transformar, filtrar, combinar o controlar la frecuencia de sus emisiones.&lt;/p&gt;
&lt;p&gt;Esta aproximación es útil cuando una interacción puede producir muchos valores a lo largo del tiempo. Una promesa representa un resultado único; un observable puede representar cero, uno, muchos o infinitos valores, además de errores y finalización.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;document&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;querySelector&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;&amp;gt;(&lt;span style="color:#98c379"&gt;&amp;#39;#search&amp;#39;&lt;/span&gt;)&lt;span style="color:#56b6c2"&gt;!&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;searchTerm$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;searchTerm$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;term&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Buscar:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;term&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El sufijo &lt;code&gt;$&lt;/code&gt; en &lt;code&gt;searchTerm$&lt;/code&gt; es una convención frecuente para indicar que la variable representa un flujo observable. No es obligatorio, pero mejora la legibilidad cuando conviven valores normales y streams.&lt;/p&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Usa RxJs cuando necesites componer eventos en el tiempo: entradas de usuario, sockets, polling, estado reactivo, cancelaciones, reintentos y coordinación entre múltiples fuentes asíncronas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cuándo-usar-programación-reactiva-con-rxjs"&gt;Cuándo usar programación reactiva con RxJs&lt;/h2&gt;
&lt;p&gt;RxJs aporta más valor cuando el problema se expresa naturalmente como una secuencia de emisiones. No todos los casos asíncronos requieren un &lt;code&gt;Observable&lt;/code&gt;; una petición HTTP aislada puede resolverse con &lt;code&gt;Promise&lt;/code&gt; sin introducir más abstracción. El punto fuerte de RxJs aparece cuando necesitas componer varias señales y mantener control explícito sobre su ciclo de vida.&lt;/p&gt;
&lt;p&gt;Casos comunes de uso:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Eventos de interfaz de usuario&lt;/strong&gt;: clicks, movimientos del mouse, inputs, scroll o drag and drop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notificación de cambios en objetos o estado compartido&lt;/strong&gt;: propagación de cambios hacia múltiples consumidores.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comunicación por sockets&lt;/strong&gt;: mensajes que llegan indefinidamente y deben procesarse con filtros o transformaciones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flujos de información&lt;/strong&gt;: secuencias que pueden combinar datos de red, timers, cache y eventos locales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control de concurrencia&lt;/strong&gt;: cancelación de peticiones obsoletas, serialización de operaciones o limitación de frecuencia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consideremos un autocompletado. Cada tecla puede disparar una solicitud de red, pero no todas las solicitudes siguen siendo relevantes. RxJs permite aplicar &lt;code&gt;debounceTime&lt;/code&gt;, eliminar valores repetidos con &lt;code&gt;distinctUntilChanged&lt;/code&gt; y cancelar peticiones previas con &lt;code&gt;switchMap&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;query$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fromEvent&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;InputEvent&lt;/span&gt;&amp;gt;(&lt;span style="color:#e06c75"&gt;searchInput&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;event&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;target&lt;/span&gt; &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;HTMLInputElement&lt;/span&gt;).&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;trim&lt;/span&gt;()),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;debounceTime&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;300&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;distinctUntilChanged&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;switchMap&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch&lt;/span&gt;(&lt;span style="color:#98c379"&gt;`/api/search?q=&lt;/span&gt;&lt;span style="color:#98c379"&gt;${&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;encodeURIComponent&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;query&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;`&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La implementación expresa la intención del flujo: capturar entrada, esperar estabilidad, evitar duplicados y ejecutar la consulta vigente. La lógica queda declarativa y evita coordinación manual con banderas de estado mutable.&lt;/p&gt;
&lt;h2 id="elementos-de-las-extensiones-reactivas"&gt;Elementos de las extensiones reactivas&lt;/h2&gt;
&lt;p&gt;RxJs organiza su modelo alrededor de tres piezas principales: &lt;strong&gt;Observables&lt;/strong&gt;, &lt;strong&gt;Subscribers&lt;/strong&gt; y &lt;strong&gt;Operators&lt;/strong&gt;. Entender la responsabilidad de cada una evita mezclar producción de datos, consumo y transformación en el mismo bloque de código.&lt;/p&gt;
&lt;h3 id="observables-la-fuente-de-información"&gt;Observables: la fuente de información&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;Observable&lt;/strong&gt; representa una fuente de valores a lo largo del tiempo. Puede emitir múltiples valores, un único valor o ninguno. También puede emitir un error o completar su ciclo de vida.&lt;/p&gt;
&lt;p&gt;Sus propiedades principales son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Puede ser finito o infinito.&lt;/li&gt;
&lt;li&gt;Puede emitir de forma síncrona o asíncrona.&lt;/li&gt;
&lt;li&gt;Puede notificar valores, errores y finalización.&lt;/li&gt;
&lt;li&gt;Puede encapsular detalles internos como eventos DOM, sockets, timers o APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;new&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Observable&lt;/span&gt;&amp;lt;&lt;span style="color:#e06c75"&gt;number&lt;/span&gt;&amp;gt;((&lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;next&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;subscriber&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En este ejemplo, &lt;code&gt;counter$&lt;/code&gt; define la fuente de emisiones. La ejecución real ocurre cuando alguien se suscribe; antes de eso, solo existe la definición del flujo.&lt;/p&gt;
&lt;h3 id="subscribers-consumidores-del-flujo"&gt;Subscribers: consumidores del flujo&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;Subscriber&lt;/strong&gt; consume las emisiones de un observable. Puede reaccionar a valores (&lt;code&gt;next&lt;/code&gt;), errores (&lt;code&gt;error&lt;/code&gt;) y finalización (&lt;code&gt;complete&lt;/code&gt;). La suscripción también representa un recurso que debe liberarse cuando el flujo deja de ser necesario, especialmente en observables infinitos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;const&lt;/span&gt; &lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;counter$&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;next&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Valor:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; (&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;error&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Error:&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;error&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;complete&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;:&lt;/span&gt; () &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;Flujo completado&amp;#39;&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;subscription&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;unsubscribe&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El consumidor no necesita conocer si los datos provienen de un arreglo, un WebSocket, un evento DOM o una API. Esa separación reduce el acoplamiento entre la fuente de datos y quienes procesan sus emisiones.&lt;/p&gt;
&lt;h3 id="operators-transformación-filtrado-y-composición"&gt;Operators: transformación, filtrado y composición&lt;/h3&gt;
&lt;p&gt;Los &lt;strong&gt;Operators&lt;/strong&gt; son funciones que permiten trabajar con observables sin mutar directamente la fuente original. Se encadenan mediante &lt;code&gt;pipe()&lt;/code&gt; y habilitan operaciones de transformación, filtrado, combinación y creación.&lt;/p&gt;
&lt;p&gt;Algunos operadores frecuentes son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Transformación: &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;scan&lt;/code&gt;, &lt;code&gt;groupBy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Filtrado: &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;distinctUntilChanged&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;, &lt;code&gt;debounceTime&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Combinación: &lt;code&gt;merge&lt;/code&gt;, &lt;code&gt;concat&lt;/code&gt;, &lt;code&gt;combineLatest&lt;/code&gt;, &lt;code&gt;zip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creación: &lt;code&gt;of&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;interval&lt;/code&gt;, &lt;code&gt;timer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#c678dd"&gt;of&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; { &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt; } &lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;rxjs/operators&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;of&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;2&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;4&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;5&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;pipe&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;filter&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;%&lt;/span&gt; &lt;span style="color:#d19a66"&gt;2&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;===&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;map&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;*&lt;/span&gt; &lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;scan&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#e06c75"&gt;value&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .&lt;span style="color:#e06c75"&gt;subscribe&lt;/span&gt;((&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;=&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;console&lt;/span&gt;.&lt;span style="color:#e06c75"&gt;log&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;value&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aquí el flujo filtra impares, transforma cada emisión y acumula el resultado. La fuente original no se modifica; cada operador devuelve un nuevo observable derivado.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La composición con operadores es una de las razones principales para adoptar RxJs: permite expresar pipelines asíncronos complejos con una semántica consistente para valores, errores y finalización.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="beneficios-de-rxjs-y-las-extensiones-reactivas"&gt;Beneficios de RxJs y las extensiones reactivas&lt;/h2&gt;
&lt;p&gt;El beneficio más visible de RxJs es evitar estructuras difíciles de mantener como el callback hell. Sin embargo, su valor no se limita a reemplazar callbacks. RxJs ofrece un modelo uniforme para tratar trabajo síncrono y asíncrono como flujos componibles.&lt;/p&gt;
&lt;p&gt;Entre sus ventajas principales están:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reduce el anidamiento de callbacks y centraliza la lógica del flujo.&lt;/li&gt;
&lt;li&gt;Permite trabajar con tareas síncronas y asíncronas bajo la misma abstracción.&lt;/li&gt;
&lt;li&gt;Usa operadores para simplificar transformación, filtrado y composición.&lt;/li&gt;
&lt;li&gt;Facilita modificar streams sin alterar el consumidor final.&lt;/li&gt;
&lt;li&gt;Mejora la legibilidad cuando el problema depende de eventos en el tiempo.&lt;/li&gt;
&lt;li&gt;Permite anexar pasos al pipeline sin reescribir toda la implementación.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Esta capacidad de composición es especialmente relevante en aplicaciones grandes. Puedes aislar responsabilidades en operadores específicos y mantener flujos más predecibles, en lugar de dispersar estado mutable entre handlers independientes.&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;RxJs no elimina la complejidad del dominio. La desplaza hacia un modelo explícito de streams. Si el problema no involucra secuencias, cancelación, coordinación o múltiples emisiones, una abstracción más simple puede ser suficiente.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="qué-es-reactivex"&gt;Qué es ReactiveX&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://reactivex.io"




 target="_blank"
 


&gt;&lt;strong&gt;ReactiveX&lt;/strong&gt;&lt;/a&gt; es una API para programación asíncrona basada en observables. Su objetivo es proporcionar una forma consistente de componer secuencias de eventos y datos a través de operadores. RxJs es la implementación de ReactiveX para JavaScript y TypeScript, documentada oficialmente en &lt;a href="https://rxjs.dev"




 target="_blank"
 


&gt;rxjs.dev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ReactiveX se apoya en tres ideas fundamentales: el patrón Observer, el patrón Iterator y la programación funcional. La combinación de estas ideas explica por qué RxJs puede representar datos que llegan en el tiempo, recorrer secuencias y aplicar transformaciones sin mutar la fuente.&lt;/p&gt;
&lt;h3 id="patrón-observer-notificación-uno-a-muchos"&gt;Patrón Observer: notificación uno a muchos&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;patrón Observer&lt;/strong&gt; define una relación uno a muchos entre objetos. Cuando el sujeto cambia su estado, notifica a todos sus observadores. En RxJs, el observable cumple el rol de fuente y cada suscripción representa un consumidor interesado en sus emisiones.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 S[Observable / Subject] --&gt;|next value| A[Subscriber A]
 S --&gt;|next value| B[Subscriber B]
 S --&gt;|next value| C[Subscriber C]
 S --&gt;|error / complete| A
 S --&gt;|error / complete| B
 S --&gt;|error / complete| C
&lt;/pre&gt;

&lt;p&gt;Este patrón resulta natural para interfaces, sockets y estado compartido. La fuente emite cambios y los consumidores reaccionan sin conocer los detalles internos de producción.&lt;/p&gt;
&lt;h3 id="patrón-iterator-operaciones-secuenciales"&gt;Patrón Iterator: operaciones secuenciales&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;patrón Iterator&lt;/strong&gt; define una forma de acceder secuencialmente a los elementos de una colección. ReactiveX toma esa idea y la proyecta sobre el tiempo: en lugar de recorrer una colección ya disponible, procesa valores conforme se emiten.&lt;/p&gt;
&lt;p&gt;Un arreglo entrega valores inmediatamente. Un observable puede entregar valores ahora, más tarde o nunca completar. Esa diferencia temporal es la razón por la que los operadores de RxJs son tan útiles para coordinar flujos asíncronos.&lt;/p&gt;
&lt;h3 id="programación-funcional-composición-sin-mutación"&gt;Programación funcional: composición sin mutación&lt;/h3&gt;
&lt;p&gt;La &lt;strong&gt;programación funcional&lt;/strong&gt; aporta la idea de construir transformaciones con funciones específicas, predecibles y sin efectos secundarios innecesarios. Operadores como &lt;code&gt;map&lt;/code&gt; y &lt;code&gt;filter&lt;/code&gt; no mutan la fuente; generan nuevos observables derivados.&lt;/p&gt;
&lt;p&gt;Esta disciplina reduce el acoplamiento y facilita razonar sobre el flujo. Cada operador cumple una responsabilidad concreta y el pipeline completo documenta el recorrido de los datos.&lt;/p&gt;
&lt;h2 id="diagrama-de-canicas-en-rxjs"&gt;Diagrama de canicas en RxJs&lt;/h2&gt;
&lt;p&gt;Los &lt;strong&gt;diagramas de canicas&lt;/strong&gt; son una convención visual para explicar cómo se comportan los observables a lo largo del tiempo. Cada línea representa un stream, cada canica representa una emisión, las barras verticales indican finalización y los operadores muestran cómo se transforma el flujo.&lt;/p&gt;




 
 
 
 &lt;div class="flex justify-center"&gt;
 &lt;img
 src="https://blog.dacadev.com/images/typescript/rxjs/intro/marble-diagram_hu_4f81c4fa30911f02.webp"
 alt="Imagen guia del contenido de la página"style="width:600px"/&gt;
 &lt;/div&gt;
 
 
 


&lt;p&gt;Este tipo de diagrama es especialmente útil para entender operadores temporales como &lt;code&gt;debounceTime&lt;/code&gt;, &lt;code&gt;throttleTime&lt;/code&gt;, &lt;code&gt;delay&lt;/code&gt;, &lt;code&gt;switchMap&lt;/code&gt;, &lt;code&gt;mergeMap&lt;/code&gt; o &lt;code&gt;concatMap&lt;/code&gt;. En lugar de describir cada emisión con texto, el diagrama permite comparar el flujo de entrada, el operador aplicado y el flujo resultante.&lt;/p&gt;
&lt;p&gt;Al leer un diagrama de canicas, considera estos puntos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;El tiempo avanza de izquierda a derecha.&lt;/li&gt;
&lt;li&gt;Cada símbolo o canica representa una emisión del observable.&lt;/li&gt;
&lt;li&gt;La barra vertical representa &lt;code&gt;complete&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Una &lt;code&gt;X&lt;/code&gt; suele representar &lt;code&gt;error&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Los operadores transforman la relación entre entrada y salida.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Cuando estudies un operador nuevo, revisa primero su diagrama de canicas y después valida el comportamiento con código. Esa secuencia reduce ambigüedad en operadores temporales y de concurrencia.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="configuración-del-proyecto-para-la-serie-rxjs"&gt;Configuración del proyecto para la serie RxJs&lt;/h2&gt;
&lt;p&gt;Para seguir la serie usaremos como base el repositorio del curso de Klerith: &lt;a href="https://github.com/Klerith/curso-rxjs-inicio"




 target="_blank"
 


&gt;Klerith/curso-rxjs-inicio&lt;/a&gt;. Este proyecto proporciona una estructura inicial para practicar RxJs sin dedicar tiempo a configurar desde cero el entorno.&lt;/p&gt;
&lt;p&gt;Puedes clonar el repositorio y preparar las dependencias con los comandos habituales:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone https://github.com/Klerith/curso-rxjs-inicio.git
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;cd&lt;/span&gt; curso-rxjs-inicio
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Si prefieres crear un proyecto propio, instala RxJs desde npm y configura TypeScript según tu stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm install rxjs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El objetivo de esta serie no es cubrir la configuración de bundlers, sino entender el modelo mental de RxJs y sus operadores. Mantener un proyecto pequeño al inicio permite enfocarse en observables, suscripciones, composición y manejo del ciclo de vida.&lt;/p&gt;
&lt;h2 id="conclusión"&gt;Conclusión&lt;/h2&gt;
&lt;p&gt;RxJs permite modelar eventos y datos asíncronos como flujos observables. Esta abstracción es útil cuando la aplicación necesita reaccionar a múltiples emisiones, coordinar fuentes, transformar datos y controlar el ciclo de vida de suscripciones.&lt;/p&gt;
&lt;p&gt;ReactiveX combina Observer, Iterator y programación funcional para construir una API coherente alrededor de streams. En el siguiente artículo profundizaremos en &lt;a href="https://blog.dacadev.com/typescript/rxjs-observables/"



 


&gt;Observables&lt;/a&gt;: cómo se crean, cuándo ejecutan, qué implica suscribirse y cómo gestionar su finalización correctamente.&lt;/p&gt;</content:encoded></item></channel></rss>