🚨 ¡Nueva review! ¡Mi teclado ideal! ⌨️ Perfecto para programar, el Logitech MX Keys S . ¡Échale un ojo! 👀

Tipos Avanzados en TypeScript: Arrays, Tuplas y Combinaciones

Union Types, Intersection Types, Arrays tipados y Tuplas

Escrito por domin el 17 de marzo de 2026

Quinto y último post de la serie TypeScript y aquí es donde juntamos todo lo que hemos aprendido y le damos una vuelta más. Si vienes siguiendo desde el principio (post 1, post 2, post 3, post 4), ya sabes tipar variables, funciones, callbacks y objetos. Ahora vamos a aprender a combinar tipos, a tipar arrays como el señor manda, y a descubrir las Tuplas, que son una de las cosas más potentes que tiene TypeScript y que poca gente usa.

Además vamos a ver la pelea entre type vs interface y ver en qué casos se usa cada una, que es la duda más común. EA, vamos al lío.

Logo de TypeScript sobre fondo azul con código de tipos avanzados.

1. Union Types: el “O” lógico de los tipos

Los ya los hemos visto de refilón en posts anteriores, pero hoy los vamos a dominar del todo. Un Union Type dice que esto puede ser esto O aquello.

// Una variable que puede ser string O number
let id: string | number;

id = 'abc-123'; // ✅ Es string
id = 42; // ✅ Es number
id = true; // ❌ Error: Type 'boolean' is not assignable
//    to type 'string | number'

Hasta aquí fácil, pero lo interesante viene cuando quieres usar esa variable, porque TypeScript no te deja hacer lo que quieras si no sabe qué tipo es la variable en ese momento:

let id: string | number = 'abc-123';

// ❌ Error: Property 'toUpperCase' does not exist on type 'string | number'
id.toUpperCase();

// ✅ TypeScript necesita que lo compruebes primero
if (typeof id === 'string') {
    id.toUpperCase(); // Aquí sabe que es string
}
if (typeof id === 'number') {
    id.toFixed(2); // Aquí sabe que es number
}

Esto se llama y es una de las cosas más elegantes de TypeScript. Dentro del if (typeof id === 'string'), TypeScript sabe con seguridad que id es un string y te da el autocompletado que toca. Fuera de ese if, sigue siendo string | number y no te deja asumir nada seguro porque el entiende que puede ser cualquiera de los dos tipos.

Union Types con tipos literales

Donde los Union Types se vuelven espectacularmente útiles es combinándolos con tipos literales :

type Escala = 'local' | 'nacional' | 'galáctico';
type Estado = 'activo' | 'inactivo' | 'pendiente';

type Hero = {
    nombre: string;
    escala: Escala;
    estado: Estado;
};

const superman: Hero = {
    nombre: 'Superman',
    escala: 'galáctico', // ✅ Autocompletado con las 3 opciones
    estado: 'activo', // ✅ Autocompletado con las 3 opciones
};

const batman: Hero = {
    nombre: 'Batman',
    escala: 'continental', // ❌ Error: Type '"continental"' is not assignable
    estado: 'activo',
};

Esto ya lo vimos en el post anterior con los Type Aliases, pero fíjate en la diferencia: hemos extraído las uniones a tipos separados (Escala, Estado) para reutilizarlos. Si mañana añades 'interdimensional' a Escala, se actualiza en todos los sitios donde lo uses. DRY aplicado a los tipos.

Union Types en parámetros de funciones

Un patrón que te vas a encontrar mucho en la práctica:

// Función que acepta string O number
function formatearId(id: string | number): string {
    if (typeof id === 'number') {
        return id.toString().padStart(5, '0'); // "00042"
    }
    return id.toUpperCase(); // "ABC-123"
}

formatearId(42); // ✅ "00042"
formatearId('abc-123'); // ✅ "ABC-123"
formatearId(true); // ❌ Error

Dentro de la función, el typeof hace el narrowing y TypeScript sabe exactamente qué métodos puedes usar en cada rama. Sin el if, te obligaría a usar solo métodos comunes a string y number (que son pocos).


2. Intersection Types: el “Y” lógico de los tipos

Si Union Types son el “O” (|), los son el “Y” (&). Un Intersection Type dice que esto tiene que ser esto Y aquello a la vez.

type Persona = {
    nombre: string;
    edad: number;
};

type Empleado = {
    empresa: string;
    cargo: string;
    salario: number;
};

// PersonaEmpleado tiene TODAS las propiedades de ambos tipos
type PersonaEmpleado = Persona & Empleado;

const yo: PersonaEmpleado = {
    nombre: 'Domin',
    edad: 28,
    empresa: 'MiEmpresa',
    cargo: 'Developer',
    salario: 22000,
};
// ✅ Tiene todo: nombre, edad, empresa, cargo, salario

Es como hacer un merge de dos tipos. El resultado es un tipo que requiere todas las propiedades de ambos, y si te alguna, error:

const incompleto: PersonaEmpleado = {
    nombre: 'Pepe',
    edad: 30,
    empresa: 'OtraEmpresa',
    // ❌ Error: Type is missing the following properties
    //    from type 'Empleado': cargo, salario
};

Intersection para extender tipos

Este es un patrón que se usa mucho para crear tipos más concretos a partir de tipos base:

type EntidadBase = {
    readonly id: string;
    createdAt: Date;
    updatedAt: Date;
};

type Usuario = EntidadBase & {
    nombre: string;
    email: string;
    rol: 'admin' | 'editor' | 'lector';
};

type Producto = EntidadBase & {
    nombre: string;
    precio: number;
    stock: number;
};

// Ambos tienen id, createdAt, updatedAt + sus propiedades específicas
const usuario: Usuario = {
    id: 'usr-001',
    createdAt: new Date(),
    updatedAt: new Date(),
    nombre: 'Domin',
    email: 'hola@domin.es',
    rol: 'admin',
};

EntidadBase funciona como un tipo padre que compartes entre Usuario y Producto, así no repites id, createdAt y updatedAt en cada tipo. Un Don’t Repeat Yourself genial!

Comparativa visual: Union vs Intersection

ConceptoUnion Type (|)Intersection Type (&)
SignificaEsto O aquelloEsto Y aquello
Con primitivosstring | number (puede ser uno u otro)string & number (imposible, es never)
Con objetosTiene las propiedades de UNO de los tiposTiene las propiedades de TODOS los tipos
Uso típicoParámetros flexibles, estados, variantesExtender tipos, combinar contratos
NarrowingNecesitas typeof/in para acceder a propiedadesAcceso directo a todas las propiedades

Ojito con esto: si haces una intersección de tipos primitivos incompatibles (string & number), el resultado es never porque no existe un valor que sea string y number a la vez. Las intersecciones solo tienen sentido con objetos en la práctica.


3. La batalla definitiva: type vs interface

Esta es la pregunta que sale en todas las entrevistas de TypeScript y la que genera más debate en X.

Ya hemos usado type para crear Type Aliases, pero existe otra forma de definir la forma de un objeto: .

// Con Type Alias
type HeroType = {
    nombre: string;
    edad: number;
    poder?: string;
};

// Con Interface (equivalente)
interface HeroInterface {
    nombre: string;
    edad: number;
    poder?: string;
}

// Las dos se usan EXACTAMENTE igual:
const thor: HeroType = { nombre: 'Thor', edad: 1500 };
const loki: HeroInterface = { nombre: 'Loki', edad: 1500 };

Hasta aquí parece exactamente la misma vaina, pero tienen diferencias importantes:

Extensión: extends vs &

// Interface usa extends para heredar
interface Animal {
    nombre: string;
    patas: number;
}

interface Perro extends Animal {
    raza: string;
    ladra: boolean;
}

// Type usa & (intersection) para combinar
type AnimalType = {
    nombre: string;
    patas: number;
};

type PerroType = AnimalType & {
    raza: string;
    ladra: boolean;
};

// Ambos resultan en el mismo tipo final
const firulais: Perro = {
    nombre: 'Firulais',
    patas: 4,
    raza: 'Labrador',
    ladra: true,
};
const toby: PerroType = {
    nombre: 'Toby',
    patas: 4,
    raza: 'Bulldog',
    ladra: true,
};

Declaration Merging: la diferencia clave

Las interfaces se pueden redeclarar y TypeScript las fusiona automáticamente, los types no:

// ✅ Interface: declaration merging
interface Config {
    host: string;
}
interface Config {
    port: number;
}
// Config ahora tiene: { host: string; port: number }

// ❌ Type: NO se puede redeclarar
type ConfigType = {
    host: string;
};
type ConfigType = {
    // Error: Duplicate identifier 'ConfigType'
    port: number;
};

Esto del declaration merging es útil en librerías, pero en tu código del día a día puede ser peligroso porque puedes modificar una interface sin querer desde otro archivo, los type son más robustos.

Lo que type puede hacer y interface no

// Type Alias para primitivos y uniones
type ID = string | number; // ✅ Interface NO puede
type Direccion = 'norte' | 'sur' | 'este'; // ✅ Interface NO puede
type Callback = (data: string) => void; // ✅ Interface NO puede

// Template Union Types
type HexColor = `#${string}`; // ✅ Interface NO puede

// Tuplas
type Coordenada = [number, number]; // ✅ Interface NO puede

¿Cuándo usar cada uno?

Usa type cuando...
  • Necesitas Union Types o tipos literales: type Estado = "activo" | "inactivo"
  • Necesitas tipos para primitivos, tuplas o funciones
  • Quieres usar Template Union Types
  • Prefieres que el tipo NO se pueda redeclarar (más predecible)
  • Trabajas con intersecciones complejas (&)
Usa interface cuando...
  • Defines la forma de un objeto simple o un contrato de API
  • Necesitas herencia con extends (más legible que &)
  • Trabajas con librerías que esperan interfaces (React, Express...)
  • Necesitas declaration merging intencionalmente

Usa type por defecto para todo y solo usa interface cuando necesites extends o estés trabajando con librerías que lo requieran. Es la convención más común en el ecosistema actual.


4. Tipando Arrays como un profesional

En TypeScript hay dos sintaxis para tipar un array:

// Sintaxis 1: tipo[] (la más común)
const numeros: number[] = [1, 2, 3, 4, 5];
const nombres: string[] = ['Ana', 'Luis', 'Domin'];

// Sintaxis 2: Array<tipo> (genérica)
const numeros2: Array<number> = [1, 2, 3, 4, 5];
const nombres2: Array<string> = ['Ana', 'Luis', 'Domin'];

Las dos hacen exactamente lo mismo. La primera (number[]) es más concisa y es la que se usa el 99% del tiempo, y la segunda (Array<number>) se ve más cuando trabajas con genéricos .

Inferencia en arrays

Como vimos en el post 2, TypeScript infiere el tipo del array mirando sus elementos:

const frutas = ['manzana', 'pera', 'plátano']; // Tipo inferido: string[]
const edades = [25, 30, 28]; // Tipo inferido: number[]
const activos = [true, false, true]; // Tipo inferido: boolean[]

// Y las protecciones funcionan automáticamente:
frutas.push(42); // ❌ Error: Argument of type 'number'
//    is not assignable to parameter of type 'string'
edades.push('lol'); // ❌ Error

Arrays con tipos mixtos

Si mezclas tipos en un array, TypeScript infiere un Union Type:

const mixto = [1, 'dos', 3, 'cuatro'];
// Tipo inferido: (string | number)[]

mixto.push(5); // ✅ number es válido
mixto.push('cinco'); // ✅ string es válido
mixto.push(true); // ❌ Error: boolean no está en la unión

Funciona, pero evita los arrays mixtos siempre que puedas. Si necesitas mezclar tipos en un array con posiciones fijas, lo que necesitas son Tuplas.

Arrays de objetos

Un patrón que vas a usar constantemente en tus proyectos:

type Hero = {
    readonly id: string;
    nombre: string;
    poder: string;
    activo: boolean;
};

const heroes: Hero[] = [
    { id: 'h-001', nombre: 'Thor', poder: 'Trueno', activo: true },
    { id: 'h-002', nombre: 'Hulk', poder: 'Fuerza', activo: true },
    { id: 'h-003', nombre: 'Loki', poder: 'Magia', activo: false },
];

// El autocompletado funciona DENTRO de los métodos del array
const activos = heroes.filter((h) => h.activo);
// activos es de tipo Hero[] ✅

const nombres = heroes.map((h) => h.nombre);
// nombres es de tipo string[] ✅

const hulk = heroes.find((h) => h.nombre === 'Hulk');
// hulk es de tipo Hero | undefined ✅
// (undefined porque find puede no encontrar nada)

Fíjate en el find: TypeScript sabe que puede devolver undefined si no encuentra el elemento, así que te obliga a comprobar antes de usar el resultado. Eso en JavaScript te enterarías cuando peta en producción, con TypeScript te enteras al escribir el código.

Arrays readonly

Si quieres un array que no se pueda modificar después de crearlo:

const colores: readonly string[] = ['rojo', 'verde', 'azul'];

colores.push('amarillo'); // ❌ Error: Property 'push' does not exist
//    on type 'readonly string[]'
colores[0] = 'negro'; // ❌ Error: Index signature in type
//    'readonly string[]' only permits reading

// ✅ Puedes leer, iterar y crear nuevos arrays
const primero = colores[0]; // ✅
const mayusculas = colores.map((c) => c.toUpperCase()); // ✅

Igual que el readonly en objetos del post anterior, esto solo funciona en tiempo de compilación. En el JavaScript generado, el array sigue siendo mutable, pero te protege de errores accidentales durante el desarrollo.


5. Tuplas: arrays con superpoderes

Una es un array donde la longitud está fijada y cada posición tiene un tipo concreto.

El problema que resuelven

Imagina que quieres representar un color RGB (rojo, verde, azul), donde cada componente es un número entre 0 y 255:

// ❌ Con un array normal
const colorMal: number[] = [255, 128, 0];
// Problema: nada impide que hagas esto:
colorMal.push(999); // ✅ Para TypeScript esto es válido
colorMal.push(42, 73, 11); // ✅ También válido... pero no tiene sentido
// Un color RGB con 6 componentes? No existe

Con un number[] solo dices esto es un array de números, pero no dices cuántos ni en qué orden, ahí entran las tuplas:

// ✅ Con una tupla
type RGB = [number, number, number];

const naranja: RGB = [255, 128, 0]; // ✅ Exactamente 3 numbers
const rojo: RGB = [255, 0, 0]; // ✅

const mal1: RGB = [255, 128]; // ❌ Error: Source has 2 element(s)
//    but target requires 3
const mal2: RGB = [255, 128, 0, 0]; // ❌ Error: Source has 4 element(s)
//    but target allows only 3
const mal3: RGB = ['ff', 128, 0]; // ❌ Error: Type 'string' is not
//    assignable to type 'number'

TypeScript valida cantidad y tipo en cada posición. Si le pasas 2 elementos en vez de 3, error. Si le pasas 4, error. Si le pasas un string donde va un number, error, tipado estricto nene.

Tuplas con tipos diferentes en cada posición

Una tupla puede tener tipos distintos en cada posición, lo vemos:

// Posición 0: string, Posición 1: number, Posición 2: number
type Coordenada = [string, number, number];

const madrid: Coordenada = ['Madrid', 40.4168, -3.7038]; // ✅
const tokio: Coordenada = ['Tokyo', 35.6762, 139.6503]; // ✅

// Cada posición tiene autocompletado del tipo correcto:
madrid[0].toUpperCase(); // ✅ string → .toUpperCase()
madrid[1].toFixed(4); // ✅ number → .toFixed()

TypeScript sabe que madrid[0] es un string y madrid[1] es un number y el autocompletado cambia según la posición. En un array normal ((string | number)[]) tendrías que hacer narrowing con typeof cada vez, con tuplas es automático.

El tablero de tres en raya: el ejemplo legendario

Este ejemplo viene directamente del curso de midulive y es el que te va a hacer entender el potencial de las tuplas, vamos a tipar un tablero de tres en raya (tic-tac-toe):

// Cada celda puede ser X, O o vacía
type CeldaValue = 'X' | 'O' | '';

// Una fila tiene exactamente 3 celdas
type Fila = [CeldaValue, CeldaValue, CeldaValue];

// El tablero tiene exactamente 3 filas
type Tablero = [Fila, Fila, Fila];

// ✅ Tablero válido:
const partida: Tablero = [
    ['X', 'O', 'X'],
    ['O', 'X', ''],
    ['', 'O', 'X'],
];

// ❌ Fila con 4 elementos:
const malTablero: Tablero = [
    ['X', 'O', 'X', ''], // Error: Source has 4 element(s)
    ['O', 'X', ''],
    ['', 'O', 'X'],
];

// ❌ Valor inválido en celda:
const trampa: Tablero = [
    ['X', 'O', 'Z'], // Error: Type '"Z"' is not assignable
    ['O', 'X', ''], //        to type 'CeldaValue'
    ['', 'O', 'X'],
];

// ❌ Solo 2 filas:
const incompleto: Tablero = [
    ['X', 'O', 'X'],
    ['O', 'X', ''],
    // Error: Source has 2 element(s) but target requires 3
];

Es super útil porque con tres líneas de tipos hemos definido una estructura que garantiza:

Si alguien intenta meter un 'Z', crear una fila de 4, o un tablero de 2 filas, TypeScript lo detecta al instante. Intenta hacer esto en JavaScript vanilla sin 15 líneas de validación manual y un test para cada caso, aquí son 3 líneas de tipos y ya.

Tuplas con etiquetas (Named Tuples)

Desde TypeScript 4.0, puedes ponerle nombres a cada posición de la tupla para que se autodocumenten:

// Sin etiquetas (menos claro)
type CoordenadaVieja = [number, number];

// Con etiquetas (mucho más claro)
type Coordenada = [latitud: number, longitud: number];

// Con etiquetas mixtas
type Respuesta = [exitoso: boolean, mensaje: string, codigo: number];

const ok: Respuesta = [true, 'Usuario creado', 201];
const error: Respuesta = [false, 'No autorizado', 401];

// Las etiquetas aparecen en el autocompletado del editor
// Al pasar el ratón por ok[0] verás: "exitoso: boolean"

Las etiquetas no cambian el comportamiento del tipo, pero mejoran mucho la legibilidad en el editor. Cuando pasas el ratón por encima de una variable, ves [exitoso: boolean, mensaje: string, codigo: number] en vez de [boolean, string, number]. Estos detallitos se agradecen bastante para entender más el contexto de lo que estamos leyendo.


6. Tuplas vs Arrays: ¿cuándo usar cada uno?

CaracterísticaArray (number[])Tupla ([number, string])
LongitudVariable (0, 1, 100...)Fija (la que definas)
Tipos por posiciónMismo tipo en todasTipo diferente en cada una
push/popPermitidoPermitido (¡cuidado!)
Uso típicoListas de datos homogéneosEstructuras fijas (coordenadas, resultados)
Autocompletado por posiciónNo (mismo tipo)Sí (tipo específico por índice)
⚠️ Gotcha: push en tuplas

TypeScript permite .push() en tuplas por compatibilidad con JavaScript. Esto puede romper la longitud fija. Usa readonly en tuplas para evitarlo: type RGB = readonly [number, number, number].

🔒 Tuplas readonly

Añade readonly delante de la tupla y TypeScript bloqueará push, pop, splice y cualquier mutación. Es la forma más segura de trabajar con tuplas.

// ❌ Tupla mutable: push rompe la garantía de longitud
type RGB = [number, number, number];
const color: RGB = [255, 128, 0];
color.push(999); // ✅ TypeScript no se queja... pero el tipo dice 3 elementos

// ✅ Tupla readonly: nadie la toca
type RGBSeguro = readonly [number, number, number];
const colorSeguro: RGBSeguro = [255, 128, 0];
colorSeguro.push(999); // ❌ Error: Property 'push' does not exist
//    on type 'readonly [number, number, number]'

7. Combinando todo: patrones del mundo real

Vamos a juntar Union Types, Intersection Types, arrays y tuplas en ejemplos que te vas a encontrar en proyectos de verdad.

Patrón 1: respuestas de API tipadas

type ApiExito<T> = {
    ok: true;
    data: T;
    status: number;
};

type ApiError = {
    ok: false;
    error: string;
    status: number;
};

// La respuesta puede ser éxito O error (Union)
type ApiRespuesta<T> = ApiExito<T> | ApiError;

type Usuario = {
    id: string;
    nombre: string;
    email: string;
};

async function fetchUsuario(id: string): Promise<ApiRespuesta<Usuario>> {
    const res = await fetch(`/api/usuarios/${id}`);
    if (!res.ok) {
        return { ok: false, error: 'Usuario no encontrado', status: res.status };
    }
    const data = await res.json();
    return { ok: true, data, status: 200 };
}

// Al usar la respuesta, TypeScript te obliga a comprobar
const respuesta = await fetchUsuario('usr-001');

if (respuesta.ok) {
    // Aquí TypeScript sabe que es ApiExito<Usuario>
    respuesta.data.nombre; // ✅ Autocompletado de Usuario
    respuesta.data.email; // ✅
} else {
    // Aquí TypeScript sabe que es ApiError
    respuesta.error; // ✅ Autocompletado de error
}

Esto se llama y es uno de los patrones más potentes de TypeScript. La propiedad ok actúa como discriminante: si es true, TypeScript sabe que es ApiExito con toda su estructura; si es false, sabe que es ApiError. Autocompletado perfecto en cada rama sin un solo typeof.

Patrón 2: sistema de eventos tipado

type Evento =
    | { tipo: 'click'; x: number; y: number }
    | { tipo: 'tecla'; key: string; shift: boolean }
    | { tipo: 'scroll'; deltaY: number };

function manejarEvento(evento: Evento): void {
    switch (evento.tipo) {
        case 'click':
            // TypeScript sabe que tiene x e y
            console.log(`Click en (${evento.x}, ${evento.y})`);
            break;
        case 'tecla':
            // TypeScript sabe que tiene key y shift
            console.log(`Tecla: ${evento.key} (shift: ${evento.shift})`);
            break;
        case 'scroll':
            // TypeScript sabe que tiene deltaY
            console.log(`Scroll: ${evento.deltaY}px`);
            break;
    }
}

Cada rama del switch tiene autocompletado diferente porque TypeScript hace narrowing basándose en el valor de evento.tipo, Es magia de tipos. Esto en JavaScript serían 3 if/else rezando para que la propiedad exista, aquí vamos con seguridad.

Patrón 3: formularios con tupla de estado

type EstadoForm = readonly [valores: Record<string, string>, errores: string[], valido: boolean];

function validarFormulario(datos: Record<string, string>): EstadoForm {
    const errores: string[] = [];

    if (!datos.nombre) errores.push('El nombre es obligatorio');
    if (!datos.email?.includes('@')) errores.push('Email no válido');
    if (!datos.password || datos.password.length < 8) errores.push('Mínimo 8 caracteres');

    return [datos, errores, errores.length === 0];
}

const [valores, errores, esValido] = validarFormulario({
    nombre: 'Domin',
    email: 'hola@domin.es',
    password: '12345',
});

// Desestructuración con tipos precisos:
// valores → Record<string, string>
// errores → string[]
// esValido → boolean

if (!esValido) {
    errores.forEach((e) => console.log(`❌ ${e}`));
}

8. Errores comunes con tipos avanzados

🚨 Confundir | con &

A | B = puede ser A o B. A & B = debe ser A y B. Con objetos, union exige propiedades de uno; intersection exige propiedades de todos.

⚠️ No usar narrowing con unions

Si tienes string | number, comprueba con typeof antes de usar métodos. TypeScript te obliga por tu bien.

🔒 Olvidar readonly en tuplas

Sin readonly, puedes hacer .push() en una tupla y romper la garantía de longitud fija. Siempre marca las tuplas como readonly.

💡 Usar arrays donde van tuplas

Si tu estructura tiene longitud fija y tipos por posición (coordenadas, RGB, resultado de función), usa una tupla. Los arrays son para listas de longitud variable.


9. Checklist: domina los tipos avanzados

0/11 — 0% blindado

Conclusión: cerramos la serie

Y hasta aquí la serie de TypeScript. En cinco posts hemos pasado de no saber qué es TypeScript a dominar los tipos avanzados, vamos a hacer un repaso rápido de todo lo que llevamos en el zurrón:

1️⃣ Post 1

¿Qué es TypeScript? — Qué es, por qué usarlo, compilación vs ejecución.

2️⃣ Post 2

Tipos e Inferencia — Tipos básicos, inferencia, any vs unknown.

3️⃣ Post 3

Funciones — Parámetros, retornos, callbacks, void vs never.

4️⃣ Post 4

Objetos y Type Aliases — Contratos, readonly, Template Union Types.

5️⃣ Post 5 (este)

Tipos avanzados — Union, Intersection, type vs interface, arrays, tuplas.

🚀 Siguiente paso

Aplica TypeScript en tu próximo proyecto. Empieza con algo pequeño y ve añadiendo tipos.

Si has llegado hasta aquí y has ido practicando con los ejemplos, ya tienes una base sólida de TypeScript que el 80% de los desarrolladores no tienen. Ahora sabes tipar funciones con callbacks, crear contratos con Type Aliases, usar Template Union Types, hacer narrowing con discriminated unions y tipar tableros de tres en raya con tuplas, un mundo de virguerías nene.

Lo que queda por delante son los genéricos (el <T> que hemos visto de refilón), los utility types (Partial, Pick, Omit, Record…) y patrones más avanzados. Pero eso ya es para otra serie. Con lo que tienes ahora puedes empezar cualquier proyecto con TypeScript y vas a saber algo más que tipar con string y number.

Toda esta serie está basada en el pedazo de curso gratuito de midudev en YouTube. Si quieres verlo en vídeo y profundizar más, te dejo el enlace: Curso de TypeScript de midudev. Gente como midu que se curran contenido gratuito de esta calidad merecen todo el apoyo.

EA, nos vemos en los bares! 🍻


Pon a prueba lo aprendido

1. ¿Qué significa el operador | en un tipo como string | number?

2. ¿Qué hace el operador & con dos tipos de objetos?

3. ¿Qué es narrowing en TypeScript?

4. ¿Qué puede hacer type que interface NO puede?

5. ¿Qué garantiza una tupla type RGB = [number, number, number]?

6. ¿Cómo evitas que se haga push en una tupla?

7. ¿Qué es un Discriminated Union?