Los tipos unión en TypeScript permiten que una variable o una función acepten múltiples tipos de datos. Esto nos da flexibilidad para definir tipos y nos ayuda en situaciones donde los valores pueden ser de más de un tipo.
TypeScript sigue realizando verificaciones de tipos en tiempo de compilación, por lo que conservamos la mayoría de ventajas de tipado estático.
Declaración de tipos unión
Para declarar un tipo unión, se utiliza el operador de barra vertical (|
) entre los tipos que se quieren combinar. Esto indica que una variable puede ser de uno u otro tipo.
let valor: number | string;
valor = 42; // Correcto
valor = "texto"; // Correcto
valor = true; // ❌ Error: El tipo 'boolean' no se puede asignar al tipo 'number | string'.
En el ejemplo anterior, la variable valor
puede contener un número o una cadena de texto, pero no un valor booleano.
Uso de tipos unión en funciones
Las funciones también pueden utilizar tipos unión para sus parámetros y valores de retorno.
function imprimirValor(valor: number | string): void {
console.log(valor);
}
imprimirValor(123); // Correcto
imprimirValor("cadena"); // Correcto
imprimirValor(true); // ❌ Error: El tipo 'boolean' no se puede asignar al tipo 'number | string'.
Tipos unión en propiedades de objetos
Podemos utilizar tipos unión en las propiedades de interfaces y tipos para dotar de flexibilidad de las propiedades dentro de un objeto.
interface Producto {
id: number;
nombre: string;
precio: number | string; // La propiedad precio puede ser un número o una cadena
}
// product1 tiene number como precio
let producto1: Producto = {
id: 1,
nombre: "Producto A",
precio: 100
};
// product1 tiene string como precio
let producto2: Producto = {
id: 2,
nombre: "Producto B",
precio: "Cien dólares"
};
En este ejemplo, la propiedad precio
del objeto Producto
puede ser un número o una cadena de texto.
Narrowing (reducción de tipos)
Cuando se trabaja con tipos unión, lo normal es que en algún momento tengamos que determinar el tipo específico de una variable en tiempo de ejecución.
Esto se conoce como “narrowing” (reducción de tipos) y se puede lograr utilizando verificaciones de tipo (type guards
)
Uso de typeof
El operador typeof
es útil para reducir tipos cuando se trabaja con tipos primitivos como números y cadenas de texto.
function procesarValor(valor: number | string): void {
// Verifica si el valor es un número
if (typeof valor === "number") {
console.log(`El valor es un número: ${valor}`);
} else {
// Si no es un número, debe ser una cadena de texto
console.log(`El valor es una cadena: ${valor}`);
}
}
procesarValor(123); // El valor es un número: 123
procesarValor("texto"); // El valor es una cadena: texto
Uso de instanceof
El operador instanceof
se utiliza para verificar si un objeto es una instancia de una clase específica, lo cual es útil para la reducción de tipos en clases y objetos complejos.
class Perro {
ladrar() {
console.log("Guau!");
}
}
class Gato {
maullar() {
console.log("Miau!");
}
}
function hacerSonido(animal: Perro | Gato): void {
// Verifica si el animal es una instancia de Perro
if (animal instanceof Perro) {
animal.ladrar(); // Si es un Perro, hace ladrar
} else {
animal.maullar(); // Si no es un Perro, debe ser un Gato y hace maullar
}
}
let miPerro = new Perro();
let miGato = new Gato();
hacerSonido(miPerro); // Guau!
hacerSonido(miGato); // Miau!
Verificaciones personalizadas
También es posible definir verificaciones de tipo personalizadas (type predicates
) para reducir tipos de manera más precisa.
// intarface pajaro
interface Pajaro {
volar(): void;
plumas: number;
}
// intarface pez
interface Pez {
nadar(): void;
aletas: number;
}
// Función que determina si un animal es un Pajaro
function esPajaro(animal: Pajaro | Pez): animal is Pajaro {
// Verifica si el método 'volar' está definido en el objeto
return (animal as Pajaro).volar !== undefined;
}
function hacerAlgo(animal: Pajaro | Pez): void {
if (esPajaro(animal)) {
animal.volar(); // Si es un Pajaro, vuela
} else {
animal.nadar(); // Si no es un Pajaro, debe ser un Pez y nada
}
}
Usar alias junto a tipos unión
Puedes utilizar alias de tipo para hacer que los tipos unión sean más claros y concisos.
type ID = number | string;
function obtenerUsuario(id: ID): void {
// Lógica para obtener usuario
}
En este ejemplo, creamos un Alias ID
que puede ser number
o string
.
Uniones de tipos compuestos
Los tipos unión pueden discriminar incluso cuando los tipos forman parte de otros tipos o objetos.
type ApiResponse = { data: any; error: null } | { data: null; error: string };
function manejarRespuesta(respuesta: ApiResponse): void {
if (respuesta.error) {
console.error(`Error: ${respuesta.error}`);
} else {
console.log(`Datos: ${respuesta.data}`);
}
}
let respuesta: ApiResponse = { data: { id: 1, nombre: "Luis" }, error: null };
manejarRespuesta(respuesta); // Datos: { id: 1, nombre: "Luis" }
En este ejemplo,
ApiResponse
puede ser una respuesta con datos y sin errores, o sin datos y con errores.- El el código maneja ambas posibilidades de manera adecuada.