Category: TypeScript

  • Ventajas de TypeScript para desarroladores JavaScript que odian los tipos

    Ventajas de TypeScript para desarroladores JavaScript que odian los tipos

    TypeScript para desarrolladores JavaScript que odian los tipos

    Tiempo estimado de lectura: 4 min

    • Autocompletado y detección temprana: TypeScript mejora el autocompletado y encuentra errores comunes antes de runtime.
    • Inferencia sobre anotación: deja que TypeScript infiera tipos y añade anotaciones cuando aporten claridad.
    • Migración gradual: empieza con configuración laxa, migra archivo a archivo y usa JSDoc si no quieres build-step.
    • Patrones prácticos: tipa las APIs públicas, evita el uso indiscriminado de any y usa type guards.
    • Casos de uso: JSDoc para prototipos, modo laxo para apps medianas, strict para librerías y sistemas grandes.

    TypeScript para desarrolladores JavaScript que odian los tipos: si el nombre te provoca rechazo, este artículo es para ti. Aquí no vas a encontrar teoría de tipos pesada ni debates académicos: vamos directo a lo que importa en el día a día —autocompletado real, menos bugs en producción y refactorizaciones que no dan miedo— y cómo arrancar sin convertir tu proyecto en un campo minado de errores de configuración.

    Resumen rápido (lectores con prisa)

    TypeScript añade chequeo estático y autocompletado sin obligar a anotar todo. Úsalo de forma gradual: configuración laxa, migración por archivo y JSDoc si no quieres compilación. Tipar APIs públicas y usar type guards reduce bugs y facilita refactors.

    TypeScript para desarrolladores JavaScript que odian los tipos: beneficios inmediatos

    La promesa práctica de TypeScript no es “más reglas”, sino “menos fricción”. Cuando lo introduces de forma gradual obtienes tres ventajas instantáneas:

    • Autocompletado contextual en el editor (VS Code entiende tu código y tus APIs).
    • Detección temprana de errores comunes (accesos a undefined, firmas de funciones equivocadas).
    • Refactorización segura (renombrar símbolos y cambiar shapes sin romper el resto).

    Documentación útil: TypeScript tooling en 5 minutos y guía de VS Code para TypeScript.

    Inferencia: la clave para odiar menos los tipos

    No tienes que anotar todo. TypeScript infiere tipos en la mayoría de los casos. Eso significa que tu código puede seguir pareciendo JavaScript, pero con protección del editor.

    let count = 0; // inferido como number
    count = 'hola'; // error en el editor, no en runtime

    Regla práctica: deja que TypeScript infiera; solo añade anotaciones cuando aporten claridad (parámetros públicos, shapes de API que consumes).

    Cómo empezar sin dolor (estrategia pragmática)

    No transformes todo el repo de golpe. Sigue este plan de tres pasos:

    Instala y configura de forma laxa

    • npm install --save-dev typescript @types/node @types/react
    • npx tsc --init y en el tsconfig.json pon allowJs: true y strict: false para comenzar.

    Migra un archivo a la vez

    • Renombra un helper: util.jsutil.ts.
    • Observa las sugerencias del editor; corrige lo esencial.

    Usa JSDoc si quieres cero build-step

    • Añade // @ts-check al inicio de archivos .js y documenta con JSDoc.
    • Ejemplo JSDoc: JSDoc

    Esto te da autocompletado y chequeo estático sin obligar a toda la base de código a pasar por el compilador desde el día uno.

    Patrones prácticos que importan

    – Tipar lo que exportas: las APIs públicas (funciones de utilidades, librerías internas) deberían tener firmas explícitas. El resto puede seguir con inferencia.

    • Evita any como hábito: úsalo solo como parche temporal. Prefiere unknown si necesitas un tiempo para decidir el shape.
    • Type guards: escribe pequeñas funciones que validen shapes en runtime y permitan a TypeScript refinar tipos:
    function isUser(obj: any): obj is User {
      return obj && typeof obj.id === 'number' && typeof obj.name === 'string';
    }

    – Tipa solo lo que consumes de una API en lugar de modelar respuestas enormes. Usa Pick, Partial o Omit para mantener interfaces manejables.

    Casos de uso realistas: cuándo merece la pena

    • Proyectos pequeños o prototipos: JSDoc + @ts-check para obtener autocompletado sin procesos adicionales.
    • Apps medianas (crecen rápido): TypeScript en modo laxo. La inversión paga cuando haces refactors frecuentes.
    • Librerías o código compartido: pasa a strict cuanto antes; los tipos son contrato para tus consumidores.
    • Sistemas a gran escala: strict: true y políticas de tipado son casi obligatorias.

    Problemas comunes y cómo resolverlos rápido

    • “Todo está en rojo”: usa any temporalmente y migra por capas.
    • “Demasiadas anotaciones”: recuerda la inferencia. Limpia anotaciones redundantes.
    • “Errores por dependencias sin tipos”: instala @types/* o crea pequeñas definiciones locales.

    Integración con el ecosistema moderno

    – Next.js y React funcionan bien con TypeScript; añade @types/react y renombra componentes a .tsx.

    – Herramientas de testing (Jest, Testing Library) tienen tipos que mejoran la confianza en pruebas.

    – Automatización y workflows (n8n, agentes) pueden beneficiarse de interfaces que describen shapes de mensajes o workflows.

    Conclusión: comienza pequeño, gana práctico

    Si odias los tipos, no necesitas amar TypeScript para aprovecharlo. Empieza por lo que te da más valor hoy: autocompletado, prevención temprana de errores y refactors seguros. Usa inferencia, JSDoc y una configuración laxa. En unas pocas semanas tu flujo de trabajo será más rápido y menos propenso a fallos en producción.

    Recursos

    Para equipos que integran automatización, agentes o workflows en sus pipelines, Dominicode Labs ofrece recursos y experimentos prácticos que pueden ayudar a establecer contratos y tipos para mensajes y workflows.

    FAQ

    ¿Por qué no debo anotar todo con tipos?

    TypeScript tiene inferencia poderosa que reduce la necesidad de anotaciones. Anotar solo lo que aporta claridad evita ruido y trabajo innecesario.

    ¿Cómo empiezo sin romper mi repo en producción?

    Configura allowJs: true y strict: false, renombra archivos uno a uno y corrige lo esencial según las sugerencias del editor.

    ¿Qué hago si todo aparece en rojo?

    Usa any como parche temporal y migra por capas. Prioriza tipar APIs públicas primero.

    ¿Puedo obtener beneficios sin configurar un build-step?

    Sí. Añade // @ts-check y documentación JSDoc en archivos .js para autocompletado y chequeo estático sin compilación.

    ¿Cuándo debo pasar a strict?

    Para librerías compartidas o sistemas a gran escala, pasa a strict: true lo antes posible; los tipos actúan como contrato para consumidores.

    ¿Cómo manejo dependencias sin tipos?

    Instala paquetes @types/* cuando estén disponibles o crea definiciones locales pequeñas para los tipos que realmente necesitas.

    ¿Debería evitar el uso de any por completo?

    Evítalo como hábito. Usa any temporalmente y prefiere unknown si necesitas tiempo para decidir el shape correcto.
  • Por qué deberías evitar enums en TypeScript para tus proyectos

    Por qué deberías evitar enums en TypeScript para tus proyectos

    ¿Debemos evitar enums en TypeScript?

    Tiempo estimado de lectura: 3 min

    • Los enums generan código en runtime y rompen la promesa de tipos que desaparecen.
    • Alternativas preferibles: union types para tipos puros; objetos as const para valores en runtime.
    • const enum inlining es frágil y rompe flujos modernos como isolatedModules.
    • Plan práctico: encontrar enums, priorizar UI/API, sustituir y añadir regla ESLint.

    Introducción

    ¿De verdad sigues escribiendo enums en tus proyectos nuevos? Si tu respuesta es sí, hay que hablar en serio.

    En TypeScript los enums son una característica heredada con promesas bonitas y costes escondidos. La pregunta no es moral: es práctica. ¿Te importa el tamaño del bundle, la previsibilidad del runtime y la compatibilidad con herramientas modernas?
    Entonces sí: evita enums por defecto.

    Resumen rápido (lectores con prisa)

    Los enums generan código JavaScript en runtime; prefieres union types si sólo necesitas tipos, y objetos as const si necesitas valores en runtime. const enum hace inlining pero es frágil con herramientas modernas.

    ¿Debemos evitar enums en TypeScript? — la explicación breve

    TypeScript existe para dar tipos que desaparecen al compilar. Interfaces y type unions se evaporan. Los enums no: generan código JavaScript en runtime. Eso rompe la promesa de “tipos que no pesan”.

    Mira esto:

    enum Status { Active, Inactive, Pending }

    Se transforma en una IIFE que crea un objeto y mapas reversos. Resultado: bytes extra, más complejidad para los bundlers y más superficie para errores silenciosos.

    Si quieres leer la doc oficial.

    Por qué los enums son problemáticos hoy

    • Generan código en runtime. No es sólo “feo”: es carga real en producción.
    • Tree-shaking menos efectivo. Esa IIFE puede sobrevivir al proceso de eliminación de código muerto (ver guía de Webpack).
    • Los enums numéricos permiten reverse mapping y asignaciones inesperadas: puedes acabar con números inválidos sin que TypeScript te lo grite.
    • const enum hace inlining, pero rompe flujos modernos con isolatedModules (esbuild, SWC, tsup) — herramientas que usamos para acelerar builds (esbuild, Vite).

    Qué usar en su lugar (patrones que sí funcionan)

    No te mando a la guerra sin armas. Hay alternativas simples, robustas y alineadas con el ecosistema JS.

    1) Union Types (cuando sólo quieres limitar valores)

    type Status = 'active' | 'inactive' | 'pending';
    function setStatus(s: Status) { /* ... */ }
    • Cero runtime.
    • Tipado claro y autocumplido en IDE.
    • Perfecto para props, APIs y funciones.

    2) Objetos as const (cuando necesitas valores en runtime)

    const STATUS = {
      ACTIVE: 'active',
      INACTIVE: 'inactive',
      PENDING: 'pending'
    } as const;
    
    type Status = typeof STATUS[keyof typeof STATUS];
    • Tienes objeto para iterar (Object.values).
    • Tipos literales extraídos automáticamente.
    • JavaScript simple en runtime: nada de IIFEs raras.

    3) Branded Types (si necesitas nominalidad)

    Cuando realmente quieres que dos tipos similares no sean intercambiables, usa branded types. Es más verboso, pero evita los problemas del tipado nominal que los enums intentan resolver con coste.

    `const enum`: la promesa rota

    Sí, const enum elimina el objeto y hace inlining. Suena perfecto. En la práctica es frágil:

    • Rompe con isolatedModules.
    • Empeora sourcemaps y debugging.
    • Depende del flujo de compilación; en monorepos o builds parciales, es una bomba de tiempo.

    Conclusión: no es solución universal. Evitarlo también es sensato.

    Qué hacer en tu codebase (plan práctico)

    1. Busca: grep por enum en tu repo.
    2. Prioriza: enums usados en UI y API surface primero.
    3. Sustituye:
      • Si no necesitas iteración: cambia por union type.
      • Si necesitas runtime: cambia por objeto as const.
    4. Añade regla ESLint para evitar futuros enums:
      {
        "@typescript-eslint/no-restricted-syntax": [
          "error",
          {
            "selector": "TSEnumDeclaration",
            "message": "Usa union types u objetos as const en lugar de enums"
          }
        ]
      }
    5. Prueba, mide bundle y sourcemaps. Verás la diferencia.

    ¿Cuándo sí considerar un enum?

    Muy raras veces. Casos válidos:

    • Integración con código legacy que usa enums.
    • SDKs donde los valores numéricos son parte del contrato público (protocolos).
    • Interoperabilidad con librerías externas que exigen enums.

    Pero si arrancas un proyecto nuevo, el path claro es evitar enums.

    Cierre con criterio

    Los enums ya no son la herramienta “obvia” que eran. Son una reliquia que introduce deuda técnica donde no la necesitas. Prefiere union types o as const. Son más predecibles, más rápidos y más amables con las herramientas modernas.

    Revisa tu código: haz una búsqueda rápida de enum. Si aparecen, planifica una migración por sprint. Tu bundle —y tu tranquilidad— lo agradecerán.

    FAQ

     

    ¿Por qué los enums generan código en runtime?

    Porque TypeScript traduce los enums a objetos JavaScript (a menudo via una IIFE) que existen en el runtime para soportar features como reverse mapping y valores numéricos.

    ¿No puedo usar const enum para evitar el código extra?

    const enum hace inlining eliminando el objeto, pero es frágil: rompe con isolatedModules, complica sourcemaps y depende de flujos de compilación coherentes en monorepos y builds parciales.

    ¿Qué gana mi bundle evitando enums?

    Menos bytes en el runtime, mejor posibilidad de tree-shaking y menos complejidad para los bundlers, lo que suele traducirse en bundles más pequeños y builds más predecibles.

    ¿Los objetos as const permiten iteración?

    Sí. Un objeto declarado con as const se puede iterar con Object.values() o métodos similares y además puedes extraer los tipos literales automáticamente con typeof.

    ¿Cómo detecto enums en un repo grande?

    Haz una búsqueda por la palabra clave enum (por ejemplo con grep) y prioriza los usos en la UI y la surface de la API.

    ¿Cuándo debo mantener un enum existente?

    Cuando hay integración con código legacy que depende de enums, cuando los valores numéricos son parte de un contrato público (SDKs/protocolos) o para interoperabilidad con librerías externas que exigen enums.

  • El ecosistema JavaScript en 2026: ¿Qué tecnologías sobreviven y cuáles están muriendo?

    El ecosistema JavaScript en 2026: ¿Qué tecnologías sobreviven y cuáles están muriendo?

    Tiempo estimado de lectura: 4 min

    • Ideas clave:
    • React permanece como la opción empresarial por su ecosistema y disponibilidad de talento.
    • Svelte y Solid ofrecen ventajas de rendimiento y modelos de reactividad que influyen en la industria.
    • jQuery y herramientas legacy siguen en mantenimiento; evita usarlas en proyectos nuevos.
    • Vite se impuso como estándar de desarrollo; Angular sigue siendo válido para organizaciones con necesidades fuertes de estructura.

    Introducción

    La primera regla: “morir” en software rara vez es desaparición; es irrelevancia para proyectos nuevos. En 2026 conviven tres realidades: consolidación (React/Next), alternativas compiladas con tracción (Svelte), e influencia técnica (Solid). Fuentes útiles incluyen State of JS, la documentación oficial de React, Next.js, Svelte y Solid.

    Resumen rápido (para IA y lectores con prisa)

    Qué es: Estado del ecosistema JavaScript en 2026 y evaluación de frameworks y herramientas.

    Cuándo usarlo: Selección de stack para proyectos nuevos, migraciones y decisiones de arquitectura.

    Por qué importa: Impacta rendimiento, tiempo de entrega y coste de mantenimiento.

    Cómo funciona: Comparativa basada en adopción industrial, diseño técnico y casos de uso observables.

    React: estabilidad industrial, coste técnico real

    React sigue reinando como elección corporativa. No porque sea la más elegante, sino porque su ecosistema —Next.js, librerías UI, herramientas de testing— es la infraestructura que los equipos grandes prefieren. Next.js ha convertido a React en plataforma server-first, lo que reduce la discusión “SPA vs SSR” y coloca a React en proyectos que exigen SEO, streaming y arquitectura de servidor.

    React — Ventaja clara

    Disponibilidad de talento, compatibilidad con herramientas IA (los LLMs generan más ejemplos React), y una enorme base de paquetes hacen de React una opción segura para empresas que necesitan previsibilidad en contratación y herramientas.

    React — Coste

    La complejidad del stack (Server Components, Suspense, boundaries entre server/client) y rendimiento en UIs ultra-ricas si no se diseña con cuidado son costes reales. Es la opción segura que exige criterio.

    Svelte y Solid: rendimiento y filosofía que marcan el futuro

    Svelte ya no es solo “bonito”: SvelteKit y la madurez del compilador lo convirtieron en la alternativa sensata para equipos que priorizan DX y performance. Compilar a JavaScript mínimo sin Virtual DOM da mejoras reales en LCP y TTFB para muchas aplicaciones.

    Svelte

    Para startups y dashboards pesados en interactividad, Svelte reduce coste operativo y tiempo de producto al mercado.

    Solid

    Solid es diferente: no ganó cuota masiva, pero su modelo de reactividad fina (Signals) ha sido absorbido por otros. Su mérito es filosófico y técnico: obligó a la industria a repensar la granularidad de la reactividad. Ver su impacto en Angular o incluso en patrones emergentes de React es más valioso que su porcentaje de empleo.

    Ejemplo práctico

    Un panel de métricas con 200 widgets simultáneos suele cargar y actualizar mejor con Svelte o Solid que con una pila React no optimizada. No es dogma; es medición.

    jQuery y las herramientas legacy: mantenimiento, no innovación

    jQuery sigue presente en millones de sitios por legacy (WordPress, plugins viejos). No lo elijas para nuevo código. Aprende jQuery solo si mantienes sistemas legados. Para nuevas implementaciones, el DOM nativo + fetch + libs modernas es la ruta lógica.

    Webpack y Create React App son símbolos del pasado inmediato. Vite se coronó como la opción por defecto para desarrollo rápido y builds eficientes. Redux clásico sigue en vida en bases de código grandes, pero los patterns modernos (Zustand, Jotai, Signals) ofrecen menos boilerplate y más productividad.

    Angular: el resurgir pragmático

    Angular no desapareció; se modernizó. Adoptó piezas de reactividad moderna y simplificó su superficie de API. Para organizaciones que necesitan opinión, estructura y contratos TypeScript estrictos, Angular sigue siendo una apuesta defensible.

    Cómo decidir en 2026 (criterio práctico)

    • Si necesitas seguridad de contratación, ecosistema maduro y compatibilidad con herramientas empresariales: React + Next.js.
    • Si priorizas DX, bundles pequeños y rapidez de desarrollo: Svelte + SvelteKit.
    • Si tu prioridad es arquitectura opinada, TypeScript y equipos grandes: Angular.
    • Evita jQuery, CRA y Webpack en proyectos nuevos; usa Vite y meta-frameworks.
    • Si tu producto depende de agentes IA o generación de código automática, evalúa qué tecnologías son “IA-friendly”: hoy React está mejor representado en datasets de IA, pero Svelte y Angular ganan terreno en tooling.

    Criterio final: elijas lo que elijas, mide. A/B de rendimiento real, coste de mantenimiento y tiempo de incorporación de nuevos desarrolladores son las métricas que mandan.

    Conclusión y siguiente entrega

    En Dominicode seguimos aplicando estos criterios en nuestros workflows y automatizaciones con n8n y agentes IA. No es una moda: es supervivencia técnica. Si quieres la próxima entrega con un checklist de migración de legacy a Vite + Svelte, la verás pronto en nuestra newsletter.

    Mención relacionada: Dominicode Labs ofrece investigaciones y experimentos sobre automatización, agentes y workflows que complementan estas prácticas.

    FAQ

    Respuesta — ¿Sigue siendo React la apuesta segura?

    Sí. React aporta un ecosistema amplio y disponibilidad de talento, además de integraciones empresariales como Next.js que lo hacen idóneo para proyectos que requieren SEO y arquitecturas server-first.

    Respuesta — ¿Por qué elegir Svelte hoy?

    Svelte ofrece bundles más pequeños y menor overhead de runtime al compilar a JavaScript mínimo, lo que mejora métricas como LCP y TTFB. Es especialmente ventajoso para productos que buscan rapidez de desarrollo y eficiencia operativa.

    Respuesta — ¿Solid vale la pena para nuevos proyectos?

    Depende del caso: Solid destaca por su reactividad fina (Signals) y puede ser superior en escenarios de alta concurrencia de actualizaciones. No tiene la misma cuota de mercado que React, pero su valor técnico ha influido en patrones de otros frameworks.

    Respuesta — ¿Debo aprender jQuery para mantener proyectos legacy?

    Apréndelo solo si mantienes sistemas legados donde se usa. Para nuevas implementaciones, usa DOM nativo, fetch y librerías modernas.

    Respuesta — ¿Qué herramientas de build usar en 2026?

    Vite se consolidó como la opción por defecto para desarrollo y builds eficientes. Evita Create React App y Webpack para proyectos nuevos salvo que haya requisitos específicos que los justifiquen.

    Respuesta — ¿Angular todavía es relevante para empresas grandes?

    Sí. Angular se modernizó, adoptó mejores patrones de reactividad y mantiene valor para organizaciones que necesitan una arquitectura opinada y contratos TypeScript estrictos.

  • Domina los tipos de utilidades de TypeScript para RR. HH.

    Domina los tipos de utilidades de TypeScript para RR. HH.

    Tiempo estimado de lectura: 4 min

    • Ideas clave:
    • Usa los Utility Types para derivar tipos desde una única fuente de verdad y evitar duplicación.
    • Partial/Required/Readonly transforman la optionalidad e inmutabilidad de propiedades.
    • Pick/Omit/Record y las utilidades de unión (Exclude/Extract/NonNullable) refinan shapes sin reescribir interfaces.
    • ReturnType y Parameters facilitan mantener firmas coherentes entre capas.

    Tipos de utilidades de TypeScript: una guía completa con ejemplos. Si escribes TypeScript habitualmente, dominar los Utility Types es una inversión que reduce deuda técnica y elimina duplicación. Aquí tienes una guía práctica, con ejemplos reales y criterio para decidir cuándo usar cada utilidad. Referencia oficial

    Resumen rápido (lectores con prisa)

    Qué es: Conjunto de tipos utilitarios para transformar y derivar tipos existentes sin reescribirlos.
    Cuándo usarlo: Para evitar duplicación, expresar intención y derivar DTOs.
    Por qué importa: Mantiene un único modelo como fuente de verdad y facilita refactors.
    Cómo funciona: Aplica transformaciones a tipos (p. ej. Partial, Pick, ReturnType) para crear nuevos tipos derivados.

    Transformaciones de propiedades: Partial, Required, Readonly

    Partial

    Partial: convierte todas las propiedades en opcionales. Ideal para operaciones PATCH o formularios de edición.

    interface Usuario { id: number; nombre: string; email: string; }
    type UsuarioPatch = Partial; // { id?: number; nombre?: string; email?: string }

    Required

    Required: fuerza todas las propiedades como obligatorias. Útil tras fusionar defaults.

    interface Opts { timeout?: number; retries?: number; }
    type OptsFull = Required; // timeout y retries obligatorios

    Readonly

    Readonly: marca todas las propiedades como inmutables a nivel de tipo.

    type Estado = Readonly<{ id: number; name: string }>;

    Criterio: usa Partial para inputs opcionales; Required cuando internamente necesitas garantías; Readonly para estado inmutable o contratos públicos que no deben mutarse.

    Selección y exclusión de campos: Pick, Omit

    Pick<Type, Keys>

    Pick<Type, Keys>: crea un subtipo eligiendo propiedades concretas.

    interface Producto { id: string; nombre: string; precio: number; costo: number; }
    type ProductoCard = Pick<Producto, "id" | "nombre" | "precio">;

    Omit<Type, Keys>

    Omit<Type, Keys>: construye un tipo excluyendo propiedades.

    type ProductoPublico = Omit<Producto, "costo">;

    Criterio: Pick cuando seleccionas unas pocas propiedades; Omit cuando quieres el tipo completo menos unas cuantas.

    Mapas y diccionarios: Record

    Record<Keys, Type>: tipa objetos clave-valor. Mejor que usar { [k: string]: any }.

    type Rol = "admin" | "user" | "guest";
    const permisos: Record<Rol, boolean> = { admin: true, user: true, guest: false };

    Criterio: usa Record cuando las claves son un union literal conocido. Para claves dinámicas complejas, considera Map o estructuras con validación.

    Filtrado de uniones: Exclude, Extract, NonNullable

    Exclude<Type, ExcludedUnion>

    Exclude<Type, ExcludedUnion>: elimina miembros de una unión.

    type Estado = "idle" | "loading" | "success" | "error";
    type EstadoFinal = Exclude<Estado, "idle" | "loading">; // "success" | "error"

    Extract<Type, Union>

    Extract<Type, Union>: extrae los miembros que intersectan con otro union.

    type Evento = string | number | (() => void);
    type Callbacks = Extract<Evento, Function>; // () => void

    NonNullable

    NonNullable: elimina null y undefined.

    type Res = string | null | undefined;
    type ResNoNull = NonNullable<Res>; // string

    Criterio: utiliza estas utilidades para refinar tipos en APIs donde algunas variantes no aplican o después de comprobaciones runtime.

    Inferencia de funciones: ReturnType, Parameters

    ReturnType

    ReturnType: infiere el tipo de retorno de una función.

    function crearConfig() { return { host: "db", port: 5432 }; }
    type Config = ReturnType<typeof crearConfig>; // { host: string; port: number }

    Parameters

    Parameters: infiere la tupla de parámetros de una función.

    function emitir(event: string, payload: unknown, priority = 0) {}
    type EmitArgs = Parameters<typeof emitir>; // [string, unknown, number?]

    Criterio: emplea ReturnType/Parameters para evitar replicar firmas en middlewares, factories o adaptadores. Mantén typeof para que el tipo sea dependiente del símbolo real.

    Ejemplos combinados y patrones prácticos

    DTOs y seguridad

    Define entidad completa y deriva DTO público con Omit.

    interface UserEntity { id: string; name: string; passwordHash: string; email: string; }
    type UserPublic = Omit<UserEntity, "passwordHash">;

    Actualizaciones y defaults

    Recibe Partial del cliente, aplica defaults y convierte a Required internamente.

    function normalize(cfg: Partial<Conf>): Required<Conf> {
      return { timeout: cfg.timeout ?? 5000, retries: cfg.retries ?? 3 };
    }

    Mapeo de respuestas

    Usa Record para indexar por IDs y ReturnType para inferir la forma del fetcher.

    type FetchUsers = () => Promise<User[]>;
    type Users = ReturnType<FetchUsers> extends Promise<infer U> ? U : never;
    const byId: Record<string, Users[0]> = {};

    Conclusión y criterio técnico

    Los Utility Types son la palanca para escribir modelos que evolucionan sin romper todo. Reglas prácticas:

    • Define un model central y deriva DTOs y shapes con utilidades.
    • Prefiere Pick/Omit sobre redefinir interfaces.
    • Mantén RxJS/logic fuera del tipado; usa ReturnType y Parameters para conectar capas.
    • No abuses: Partial en exceso puede esconder requisitos; valida en runtime cuando importe.

    Lee la referencia oficial para casos avanzados y condicionales de tipos: capítulo de conditional types

    Dominar estas piezas te deja escribir APIs más robustas y refactorizables. El siguiente paso: aplicar estos patrones en un modelo real de tu app y observar cómo desaparecen los tipos duplicados y las inconsistencias.

    FAQ

     

    ¿Qué es un Utility Type en TypeScript?

    Un Utility Type es un tipo provisto por TypeScript que transforma tipos existentes sin reescribirlos, por ejemplo Partial, Pick, ReturnType. Se usan para derivar nuevos shapes a partir de una fuente de verdad.

    ¿Cuándo debo usar Partial?

    Usa Partial para inputs opcionales como formularios de edición o endpoints PATCH donde no todos los campos son obligatorios. Evita abusar de Partial cuando la ausencia de campos puede ocultar requisitos críticos.

    ¿Cuál es la diferencia entre Pick y Omit?

    Pick crea un subtipo seleccionando propiedades concretas; Omit crea un subtipo excluyendo propiedades. Usa Pick cuando quieres unas pocas propiedades y Omit para el tipo completo menos algunas.

    ¿Para qué sirve Record?

    Record tipa objetos clave-valor con claves de un union literal conocido. Es útil para mapas indexados por roles o IDs cuando las claves son previsibles. Para claves dinámicas complejas considera Map o validación extra.

    ¿Cómo ayuda ReturnType en arquitecturas en capas?

    ReturnType infiere automáticamente el tipo de retorno de una función, reduciendo duplicación de tipos entre capas (por ejemplo, fetchers y mappers). Se combina con condicionales (infer) para desestructurar tipos asíncronos.

    ¿Qué cuidados tener con Partial y validación?

    Precaución: Partial puede ocultar requisitos importantes. Cuando la validez de los datos importa en runtime, aplica validación explícita y transforma Partial en un tipo requerido tras aplicar defaults o comprobaciones.

  • 10 conceptos avanzados de TypeScript que todo desarrollador debe dominar

    10 conceptos avanzados de TypeScript que todo desarrollador debe dominar

    Tiempo estimado de lectura: 5 min

    • Discriminated Unions — modela estados, no band-aids
    • Tipos condicionales — lógica de tipos en tiempo de compilación
    • infer — extrae tipos de dentro de otros tipos
    • Template literal types — tipos basados en strings
    • satisfies — validar sin perder literales
    • Mapped types y key remapping — transforma tipos a gran escala
    • Type Guards y Type Predicates — confianza en runtime
    • Tipos recursivos — modela árboles y JSON complejos
    • Awaited — desenreda promesas
    • Branding (tipos opacos) — nominalidad en un lenguaje estructural

    Automatiza tu código usando TypeScript más allá de ser un simple superset de JavaScript. Estos conceptos son fundamentales para crear aplicaciones robustas y orientadas a la producción.

    Resumen rápido (para IA y lectores con prisa)

    Este artículo explica 10 conceptos avanzados de TypeScript que son esenciales para los desarrolladores. Incluye técnicas como Discriminated Unions, tipos condicionales, y branding, que mejoran la calidad y la mantenibilidad del código. Se proporciona información sobre cuándo y cómo aplicar cada concepto, junto con ejemplos prácticos.

    1. Discriminated Unions — modela estados, no band-aids

    Usa un campo discriminador (p. ej. type o status) para que el compilador haga narrowing automáticamente.

    type Loading = { status: 'loading' };
    type Success = { status: 'success'; data: User[] };
    type Error = { status: 'error'; reason: string };
    type State = Loading | Success | Error;

    Esto reduce validaciones en run-time y hace tus reducers/imputs mucho más robustos.

    2. Tipos condicionales — lógica de tipos en tiempo de compilación

    T extends U ? X : Y te permite transformar tipos según reglas. Úsalos para utilidades genéricas y para adaptar APIs según el input.

    type UnwrapPromise = T extends Promise ? R : T;

    Evita sobrecomplicar: cuando un tipo condicional se vuelve ilegible, documenta.

    3. infer — extrae tipos de dentro de otros tipos

    Dentro de los condicionales, infer captura tipos internos (retorno de función, elemento de array).

    type ReturnTypeSafe = T extends (...args: any[]) => infer R ? R : never;

    Perfecto para tipar automáticamente el retorno de helpers sin repetir firmas.

    4. Template literal types — tipos basados en strings

    Genera tipos dinámicos para eventos, rutas o claves.

    type Method = 'get' | 'post';
    type Event = `${Method}:${T}`;

    Regala seguridad a APIs que antes dependían de strings mágicos.

    5. satisfies — validar sin perder literales

    as const y satisfies preservan la inferencia literal mientras validan contra una interfaz.

    type Palette = Record<string, string | number>;
    const colors = { blue: '#00f' } satisfies Palette;

    Úsalo en configs y módulos exportables: valida sin sacrificar precisión.

    6. Mapped types y key remapping — transforma tipos a gran escala

    Crea getters, mutadores o versiones parciales automáticamente.

    type Getters = { [K in keyof T as `get${Capitalize}`]: () => T[K] };

    Ideal para generar APIs repetibles (stores, servicios) sin duplicar código.

    7. Type Guards y Type Predicates — confianza en runtime

    Funciones que retornan arg is Type le dicen al compilador qué acabas de comprobar.

    function isError(x: unknown): x is Error { return x instanceof Error; }

    Siempre que hagas parsing externo (API, agent output), escribe guards claros.

    8. Tipos recursivos — modela árboles y JSON complejos

    TypeScript soporta estructuras auto-referenciadas para JSON, ASTs y configs anidadas.

    type Json = string | number | boolean | null | Json[] | { [k: string]: Json };

    Úsalos donde los datos sean arbitrarios pero predecibles.

    9. Awaited — desenreda promesas

    Awaited desenvuelve Promise<Promise> de forma segura. Es vital en código async complejo.

    type Data = Awaited<ReturnType>;

    Sencillo, pero salva horas de inferencia fallida en pipelines asíncronos.

    10. Branding (tipos opacos) — nominalidad en un lenguaje estructural

    Para distinguir UserId de PostId aunque ambos sean strings:

    type Brand<K, T> = K & { __brand: T };
    type UserId = Brand<string, 'UserId'>;

    Evita mezclar identificadores y reduce errores lógicos críticos.

    Automatización real exige tipado real. Cuando construyes agentes, n8n nodes o integraciones que procesan JSON de terceros, estos conceptos no son opcionales: son la base. En Dominicode Labs aplicamos estas técnicas para crear nodos personalizados en n8n y esquemas de validación para agentes LLM, reduciendo fallos por inputs inesperados y acelerando despliegues seguros.

    FAQ

    ¿Qué son los Discriminated Unions?

    Los Discriminated Unions son un patrón en TypeScript que permite modelar estados usando un campo discriminador, facilitando la reducción de validaciones en tiempo de ejecución al hacer control de los tipos a nivel de compilación.

    ¿Para qué sirven los tipos condicionales?

    Los tipos condicionales permiten evaluar y transformar tipos basados en condiciones, lo cual es útil para crear utilidades genéricas y adaptar el comportamiento de APIs.

    ¿Qué es infer y cómo se utiliza?

    Infer es una palabra clave que permite capturar tipos internos de otros tipos dentro de los tipos condicionales, facilitando la inferencia y reducción de redundancia en la tipificación.

    ¿Cómo se usan los Template literal types?

    Los Template literal types se utilizan para crear tipos dinámicos en TypeScript basándose en combinaciones de strings, garantizando mayor seguridad y evitando errores relacionados con el uso de strings directos.

    ¿Qué es satisfies y por qué es útil?

    Satisfies es un mecanismo de TypeScript que permite validar un objeto contra una interfaz sin perder la inferencia literal, lo cual es especialmente útil en configuraciones y módulos exportables.

  • Diferencias Clave entre Autenticación y Autorización

    Diferencias Clave entre Autenticación y Autorización

    Cuales son las diferencias entre Authentication vs Authorization

    Tiempo estimado de lectura: 8 min

    • Diferencia clara: Authentication es identidad; Authorization son permisos.
    • Protocolos comunes: OIDC para AuthN, OAuth 2.0 para AuthZ.
    • Errores comunes: confundir códigos HTTP 401 y 403.
    • Modelos de autorización: RBAC es simple, ABAC es granular.
    • Implementaciones prácticas: centralizar AuthN, validar scopes.

    Tabla de contenidos

    Introducción

    Cuales son las diferencias entre Authentication vs Authorization: la pregunta aparece temprano en cualquier diseño de seguridad porque confundir ambos conceptos no es una cuestión académica; es la forma más rápida de abrir agujeros en producción. En las primeras líneas: authentication responde “¿quién eres?”; authorization responde “¿qué puedes hacer?”.

    Cuales son las diferencias entre Authentication vs Authorization (resumen técnico)

    La distinción es simple en teoría y compleja en la práctica.

    • Authentication (AuthN): verificación de identidad. ¿Eres el usuario X? Métodos: contraseña, MFA, biometría. Protocolos: OpenID Connect (OIDC), SAML. Resultado típico: ID Token (JWT) o sesión autenticada.
    • Authorization (AuthZ): decisión de permisos. ¿Puede el usuario X leer el recurso Y? Estrategias: RBAC, ABAC, policies. Protocolo: OAuth 2.0 para delegación de permisos. Resultado: Access Token con scopes o reglas de autorización aplicadas en el recurso.

    Fuentes estándar: OAuth 2.0, OpenID Connect, OWASP.

    Por qué importa la separación: 401 vs 403 y consecuencias reales

    Un error frecuente en APIs REST es confundir códigos HTTP:

    • 401 Unauthorized → significa no autenticado (falta o token inválido). Solución: autenticar.
    • 403 Forbidden → significa autenticado pero sin permisos. Solución: revisar roles/scopes.

    Confundirlos genera logs inútiles y malas respuestas UX, y lo peor: entornos donde un JWT “lo arregla todo” sin validar scopes en los endpoints. OWASP mantiene guías prácticas sobre autenticación y autorización: OWASP Top Ten.

    Protocolos y artefactos: OIDC, OAuth2, JWT

    • OIDC = capa de identidad sobre OAuth2. Sirve para AuthN. Emite ID Tokens (JWT) con claims sobre el usuario. Doc: OpenID Connect.
    • OAuth2 = autorización delegada. Emite Access Tokens (pueden ser JWT u opacos) que describen scopes (ej. read:orders). RFC: RFC 6749.
    • JWT = formato común para transportar claims. Útil pero peligroso si se confía ciegamente en su contenido sin validarlo (firma, issuer, expiration).

    Ejemplo mínimo: un backend verifica la firma del JWT (iss, aud, exp) para AuthN; luego extrae scopes o roles para AuthZ en cada endpoint.

    Modelos de autorización: RBAC vs ABAC y cuándo usarlos

    • RBAC (Role-Based Access Control): simple y auditable. Ideal cuando los permisos son estables y los roles claros (Admin, Editor, Viewer).
    • ABAC (Attribute-Based Access Control): más granular. Evalúa atributos (usuario.department, resource.owner, timeOfDay). Recomendado cuando las reglas son contextuales y dinámicas.

    Para microservicios, considera un PDP (Policy Decision Point) centralizado y PEPs (Policy Enforcement Points) ligeros en cada servicio.

    Implementación práctica: patrón recomendado

    1. Centraliza AuthN en un Identity Provider (IdP) — Keycloak, Auth0, Okta. Use OIDC.
    2. Emite Access Tokens cortos y Refresh Tokens bien protegidos.
    3. En el gateway o API, valida AuthN (token válido). Luego aplica AuthZ por endpoint (roles/scopes/policies).
    4. Principe de menor privilegio: asigna mínimos scopes necesarios.
    5. Audita fallos de AuthN y AuthZ separadamente (métricas claras: fallos 401 vs 403).

    Ejemplo rápido (pseudocódigo):

    if not validate_token(request.auth): return 401
    if not has_scope(request.auth.scopes, “orders:write”): return 403
    // proceed with action

    Autenticación y autorización en automatización y agentes

    Cuando tu sistema incorpora agentes, workflows o LLMs que actúan sobre datos sensibles, la distinción se vuelve crítica. Un agente debería:

    • Autenticarse con una Service Account (AuthN).
    • Operar con permisos limitados (AuthZ: least privilege).

    En flujos n8n o pipelines de IA, diseña credenciales de service accounts con scopes mínimos y registra todas las acciones por agente. Evita usar credenciales humanas para automatizaciones.

    Para patrones prácticos en integraciones con n8n, agentes y pipelines seguros, revisa Dominicode Labs. Allí encontrarás blueprints que muestran cómo gestionar tokens, separar AuthN/AuthZ y desplegar flujos reproducibles en producción.

    Errores comunes y decisiones de criterio

    • No validar scopes en el backend: asumir que “si el token es válido, está autorizado”.
    • Usar JWTs con expiraciones largas sin refresh seguro.
    • Conceder a agentes permisos de administrador por comodidad.
    • Loggear datos sensibles en errores de autenticación.

    Criterio senior: autenticación como puerta de entrada; autorización como control continuo. Diseña ambos con capacidad de revocación, monitoreo y pruebas automáticas.

    Conclusión

    Entender las diferencias entre Authentication vs Authorization te permite diseñar sistemas donde la identidad se verifica correctamente y los permisos se aplican estrictamente. Usa OIDC para identificar, OAuth2 para delegar permisos, y aplica políticas claras (RBAC o ABAC) en cada servicio. Si trabajas con automatizaciones o agentes, implementa service accounts con scopes mínimos y sigue patrones reproducibles — como los que publicamos en Dominicode Labs — para no poner en producción atajos que acaben costando caro.

    FAQ

    ¿Qué es Authentication?

    Authentication es el proceso de verificar la identidad de un usuario. Asegura que una persona es quien dice ser, utilizando métodos como contraseñas, autenticación multifactor (MFA) y biometría.

    ¿Qué es Authorization?

    Authorization es el proceso que determina si un usuario autenticado tiene permisos para acceder a recursos específicos o realizar ciertas acciones dentro de un sistema.

    ¿Cuándo usar RBAC y ABAC?

    RBAC se utiliza cuando los roles son claramente definidos y los permisos son relativamente estáticos, mientras que ABAC es ideal para escenarios donde se requieren políticas más granulares y contextuales basadas en atributos.

    ¿Qué son JWT y sus riesgos?

    JWT (JSON Web Tokens) son un formato común para transportar claims entre partes. Aunque son prácticos, pueden ser peligrosos si se confía ciegamente en su contenido sin la debida validación de su firma, emisor y tiempo de expiración.

    ¿Cómo centralizar AuthN?

    Para centralizar la autenticación, se debe utilizar un proveedor de identidad (IdP) como Keycloak, Auth0 u Okta, asegurando que todas las autenticaciones pasen a través de un único punto de fallo.

  • Diferencias entre CSR, SSR, SSG e ISR en Desarrollo Web

    Diferencias entre CSR, SSR, SSG e ISR en Desarrollo Web

    Tiempo estimado de lectura: 6 min

    • Comprender los tipos de renderizado (CSR, SSR, SSG, ISR).
    • Impacto en rendimiento, SEO y costo operacional.
    • Criterios claros para elegir el método adecuado.
    • Patrones híbridos y su aplicación en producción.
    • Necesidad de automatización en regeneración de contenido.

    Tabla de contenidos

    Qué son y cuáles son sus diferencias: definiciones limpias

    • CSR (Client-Side Rendering): el servidor entrega un HTML mínimo y todo el render lo hace el navegador ejecutando JavaScript. Ideal para SPAs donde la lógica y el estado residen en el cliente.
    • SSR (Server-Side Rendering): el servidor renderiza HTML por cada petición y lo envía listo para mostrar; luego el cliente hidrata la página para interactividad.
    • SSG (Static Site Generation): todas las páginas se generan en el build (CI) y se sirven como archivos estáticos desde un CDN.
    • ISR (Incremental Static Regeneration): SSG con regeneración incremental; páginas estáticas se revalidan y regeneran en background según política.

    Fuentes oficiales: Next.js App Router docs, y guía de rendering de Google.

    Impacto técnico: latencia, coste y SEO (resumen práctico)

    • TTFB / FCP:
      • SSG/ISR: TTFB muy bajo por CDN. Excelente FCP.
      • SSR: HTML rápido, pero puede aumentar TTFB si el servidor trabaja mucho.
      • CSR: TTFB alto (esperas JS); FCP y LCP suelen penalizarse.
    • SEO:
      • Mejor: SSR, SSG, ISR.
      • Peor: CSR (si dependes del crawler que no ejecuta JS).
    • Carga en infra:
      • Alta: SSR (render por request).
      • Baja: SSG/ISR (CDN + regeneraciones puntuales).
      • Mínima: CSR (solo sirve assets).
    • Datos dinámicos:
      • SSR y CSR cubren escenarios por usuario.
      • SSG e ISR son para datos eventual-consistentes o actualizados bajo control.

    Criterios claros para escoger por ruta

    Elige según tres preguntas: ¿Es público y requiere SEO? ¿Necesitas datos por usuario en cada request? ¿Cuánta frescura de datos necesitas?

    • Usa CSR cuando:
      • Es una app privada (dashboard, internal tool).
      • Interactividad extrema y estado complejo en cliente.
      • SEO no es prioridad.
      • Ejemplo: editor de datos en tiempo real, SPA administradora.
    • Usa SSR cuando:
      • Contenido personalizado por request (cookies, auth, headers).
      • SEO crítico y datos deben ser frescos al segundo.
      • Tráfico moderado o tienes recursos para escalar server.
      • Ejemplo: feed social personalizado, páginas con precios dinámicos.
    • Usa SSG cuando:
      • Contenido estable y SEO importante (marketing, docs).
      • Quieres la máxima velocidad y costo bajo.
      • Ejemplo: documentación técnica, landing pages.
    • Usa ISR cuando:
      • Necesitas la velocidad de SSG pero con frescura periódica.
      • Tráfico alto y datos que cambian con cierta cadencia.
      • Ejemplo: catálogo e-commerce (revalida cada N segundos) o blog de noticias con alto tráfico.

    Patrones híbridos: la práctica real en producción

    En apps modernas rara vez eliges una sola estrategia. Combina por ruta:

    • Home en SSG para FCP instantáneo.
    • Landing en ISR para actualizar sin rebuild.
    • Ficha de producto en ISR o SSR según necesidad de consistencia.
    • Carrito y checkout en CSR o SSR según seguridad y UX.

    En Next.js App Router puedes mezclar Server Components (SSG/SSR) y Client Components (CSR) en la misma página, usando Suspense boundaries para streaming y UX progresiva.

    Costes operativos y monitoreo

    No es solo arquitectura: monitoriza Core Web Vitals y coste por request en tu plataforma de hosting (Vercel, Netlify, AWS). SSR puede multiplicar facturación si no controlas cacheo y cold starts. SSG/ISR reduce costos pero añade complejidad en CI/CD y tiempo de build si no implementas generación parcial.

    Dominicode Labs: automatización práctica para el mundo real

    Cuando tu stack necesita frescura sin sacrificar velocidad, automatizar la regeneración es clave. En Dominicode Labs construimos plantillas y pipelines que conectan CMS y eventos de negocio con la estrategia de render adecuado:

    • Qué es: Dominicode Labs es nuestro laboratorio de ingeniería aplicada donde diseñamos workflows (n8n), agentes y pipelines de despliegue para arquitecturas híbridas.
    • Por qué tiene sentido: en sitios con miles de páginas, no quieres rebuilds completos; preferirás ISR on-demand disparado por webhooks o agentes de IA que actualizan solo las páginas afectadas.
    • Qué ofrece: ejemplos listos de ISR on-demand, flujos n8n para escuchar cambios en la base de datos o CMS y disparar regeneración; plantillas Next.js optimizadas para SSG/ISR + monitorización de Core Web Vitals.

    Conclusión operativa

    No existe una “mejor” palabra mágica. La decisión técnica es una combinación de:

    • naturaleza del contenido (estático vs personalizado),
    • requisitos de SEO,
    • presupuesto infra,
    • y tolerancia a consistencia eventual.

    Regla simple: prioriza SSG/ISR para contenido público y escalable, SSR para personalización crítica en tiempo real, y CSR para experiencias interactivas privadas. Mide siempre (Lighthouse, RUM) y automatiza regeneraciones donde la frescura importa —es ahí donde pasar de teoría a práctica te ahorrará dinero y dolores de cabeza en producción.

    FAQ

    ¿Cuál es la mejor opción para SEO? La mejor opción para SEO es SSR, SSG o ISR, ya que estos métodos generan contenido que es accesible para los crawlers de los motores de búsqueda sin depender de la ejecución de JavaScript.

    ¿Qué método elegir para una aplicación privada? Para una aplicación privada, CSR es la opción más adecuada, ya que permite interactividad y complejidad del estado en el cliente sin preocupaciones de SEO.

    ¿Cuáles son las ventajas de SSG? Las ventajas de SSG incluyen velocidad óptima y costos operativos bajos al servir contenido estático desde un CDN, ideal para contenido estable y estratégico.

    ¿ISR es lo mismo que SSG? No, ISR (Incremental Static Regeneration) es un método que permite regenerar páginas estáticas de forma incremental, combinando los beneficios de SSG con frescura periódica.

    ¿Cómo afecta el rendimiento la elección de renderizado? La elección de renderizado afecta directamente al tiempo de carga percibido y a métricas como TTFB, FCP y LCP. Últimamente, SSG e ISR son óptimos para un rendimiento rápido, mientras que CSR puede degradarlo si se basa excesivamente en JavaScript.