TypeScript

TypeScript

Tutorial TypeScript: Type aliases y aserciones de tipo

Aprende a usar alias de tipos y aserciones en TypeScript para mejorar la legibilidad y seguridad de tu código con ejemplos prácticos.

Aprende TypeScript y certifícate

Qué son y para qué sirven los alias de tipos con type

Los alias de tipos en TypeScript son una característica que nos permite crear nombres personalizados para cualquier tipo de dato. Mediante la palabra clave type, podemos definir un nombre que represente un tipo específico, ya sea simple o complejo, facilitando así la reutilización y mejorando la legibilidad del código.

Sintaxis básica

La sintaxis para crear un alias de tipo es sencilla:

type NombreDelAlias = TipoExistente;

El TipoExistente puede ser cualquier tipo válido en TypeScript: un primitivo, un objeto, una unión, una tupla, etc.  

Alias para Tipos Primitivos

Podemos crear alias para los tipos básicos que ya conocemos, aunque su utilidad principal reside en alias para tipos más complejos.

// Creamos un alias para el tipo string
type IdentificadorUsuario = string;

// Usamos el alias como si fuera el tipo original
const usuarioActualId: IdentificadorUsuario = "user_7890";

// Alias para un número, quizás representando una cantidad
type CantidadProducto = number;

let stockDisponible: CantidadProducto = 150;

En estos casos simples, el beneficio no es tan evidente, pero ayuda a introducir la sintaxis.

Alias para objetos

Una aplicación muy común y poderosa es definir la estructura de los objetos. Esto nos permite reutilizar la misma forma para múltiples variables, parámetros de función o valores de retorno.

// Define la estructura para representar un perfil de usuario
type UserProfile = {
  id: string;
  name: string;
  age: number;
  isActive: boolean;
};

// Creamos un objeto que debe cumplir con esta estructura
const newProfile: UserProfile = {
  id: "profile_123",
  name: "Alice Smith",
  age: 30,
  isActive: true
};

// Una función que espera un objeto con esta estructura
function displayProfile(profile: UserProfile): void {
  console.log(`User: ${profile.name} (ID: ${profile.id})`);
  console.log(`Age: ${profile.age}, Is Active: ${profile.isActive}`);
}

displayProfile(newProfile);

// Si intentamos crear un objeto que no cumple la estructura, TypeScript nos avisará
/*
const incompleteProfile: UserProfile = {
  id: "profile_456",
  name: "Bob"
  // Faltan 'age' e 'isActive', TypeScript mostrará un error aquí
};
*/

Alias que Incorporan Enums

Podemos usar tipos definidos previamente, como los enums, dentro de la definición de nuestros alias de tipo. Esto es útil para estructuras que contienen un conjunto fijo de opciones.

// Usando un Enum definido previamente
enum DocumentStatus {
  Draft,    // 0
  Review,   // 1
  Published,// 2
  Archived  // 3
}

// Define un alias para un documento que incluye un campo de tipo Enum
type DocumentItem = {
  title: string;
  content: string;
  status: DocumentStatus; // Usamos el Enum aquí
  creationDate: Date;
};

const myArticle: DocumentItem = {
  title: "Type Aliases and Assertions",
  content: "...", // Contenido del artículo
  status: DocumentStatus.Review, // Asignamos un valor del Enum
  creationDate: new Date()
};

function changeDocumentStatus(doc: DocumentItem, newStatus: DocumentStatus): void {
    doc.status = newStatus;
    console.log(`Document "${doc.title}" is now in status: ${DocumentStatus[doc.status]}`);
}

changeDocumentStatus(myArticle, DocumentStatus.Published);

Alias para uniones de tipos

Los alias son especialmente útiles para definir uniones de tipos, haciendo el código más legible:

type Status = "pending" | "processing" | "completed" | "failed";

function updateOrderStatus(orderId: string, status: Status) {
  console.log(`Order ${orderId} status updated to ${status}`);
}

// Uso correcto
updateOrderStatus("order_123", "completed");

// Error de tipo - "cancelled" no es un Status válido
// updateOrderStatus("order_456", "cancelled");

Alias para funciones

Los alias de tipos también pueden describir la firma (los parámetros y el tipo de retorno) de una función. Esto es muy útil para tipar funciones de "callback" o para definir un tipo para múltiples funciones con la misma forma.

// Definimos un alias para un tipo de función
type NumberComparator = (a: number, b: number) => number;

// Creamos funciones que cumplen con este alias
const compareNumbersAsc: NumberComparator = (a, b) => a - b;
const compareNumbersDesc: NumberComparator = (a, b) => b - a;

// Una función que espera una función que cumpla con el alias NumberComparator
function sortArray(arr: number[], strategy: NumberComparator): number[] {
  // Usamos slice() para no modificar el array original (inmutabilidad - concepto de FP)
  return arr.slice().sort(strategy);
}

const numbers = [3, 1, 4, 1, 5, 9]; // Array de ejemplo
console.log("Order Asc:", sortArray(numbers, compareNumbersAsc)); // Order Asc: [ 1, 1, 3, 4, 5, 9 ]
console.log("Order Desc:", sortArray(numbers, compareNumbersDesc)); // Order Desc: [ 9, 5, 4, 3, 1, 1 ]

Alias vs Interfaces

Aunque los alias de tipos y las interfaces pueden parecer similares, tienen algunas diferencias clave:

// Alias de tipo para un objeto
type UserType = {
  id: string;
  name: string;
};

// Interfaz equivalente
interface UserInterface {
  id: string;
  name: string;
}

Las principales diferencias son:

  • Los alias de tipos pueden representar cualquier tipo, incluyendo primitivos, uniones y tuplas.
  • Las interfaces solo pueden representar objetos y clases.
  • Las interfaces se pueden extender y fusionar (declaration merging), mientras que los alias no.

Aplicaciones prácticas

Los alias de tipos son especialmente útiles en:

  • Configuraciones de aplicaciones:
type AppConfig = {
  apiUrl: string;
  timeout: number;
  features: {
    darkMode: boolean;
    notifications: boolean;
  };
};

const config: AppConfig = {
  apiUrl: "https://api.example.com",
  timeout: 3000,
  features: {
    darkMode: true,
    notifications: false
  }
};
  • Gestión de estados:
type UserState = {
  isLoading: boolean;
  data: User | null;
  error: string | null;
};

function userReducer(state: UserState, action: UserAction): UserState {
  // Lógica del reducer
  return state;
}
  • Validación de datos:
type ValidationResult = {
  valid: boolean;
  errors: string[];
};

function validateUser(user: User): ValidationResult {
  const errors: string[] = [];
  
  if (!user.email.includes('@')) {
    errors.push('Invalid email format');
  }
  
  if (user.age < 18) {
    errors.push('User must be at least 18 years old');
  }
  
  return {
    valid: errors.length === 0,
    errors
  };
}

Los alias de tipos son una herramienta fundamental en TypeScript que mejora la mantenibilidad y legibilidad del código, permitiendo crear abstracciones de tipos personalizadas que se adaptan perfectamente a las necesidades específicas de cada proyecto.

Beneficios de Usar Alias de Tipos

  • Readability: Dan nombres descriptivos a tipos complejos, haciendo el código más fácil de entender.
  • Reusability: Evitan repetir la misma definición de tipo varias veces.
  • Maintainability: Si una estructura de datos cambia, solo necesitas actualizar la definición del alias en un lugar.

Los alias de tipos son una herramienta fundamental para construir un código TypeScript más limpio, organizado y fácil de mantener.

Aserciones de tipo con 'as' y Guardas de Tipo

En TypeScript, el compilador intenta inferir el tipo de tus variables lo mejor posible. Sin embargo, hay situaciones en las que tú, como desarrollador, tienes más información sobre el tipo real de un valor que el compilador. En estos casos, puedes usar aserciones de tipo para indicarle a TypeScript que trate ese valor como un tipo específico.

Las guardas de tipo, por otro lado, son mecanismos de TypeScript (a menudo combinados con código JavaScript estándar como typeof o instanceof) que ayudan al compilador a refinar automáticamente el tipo de una variable dentro de bloques condicionales, haciendo el código más seguro y a menudo eliminando la necesidad de aserciones.

Aserciones de Tipo con 'as'

Una aserción de tipo es una forma de decirle al compilador: "Confía en mí, sé de qué tipo es este valor". TypeScript no realiza ninguna comprobación adicional en tiempo de ejecución cuando usas una aserción; es puramente una directiva para el compilador durante la fase de desarrollo/compilación.

La sintaxis más común para las aserciones de tipo es usando la palabra clave as:

let someValue: any = "This is a string"; // Valor inicial

// Le decimos a TypeScript que trate 'someValue' como un string
let stringLength: number = (someValue as string).length;

console.log(stringLength); // Imprime la longitud

let anotherValue: unknown = 123; // Valor unknown

// Con 'unknown', a menudo necesitas una aserción o una guarda para usar el valor
// Aquí le decimos a TypeScript que lo trate como number para usar toFixed
let fixedValue: string = (anotherValue as number).toFixed(2);

console.log(fixedValue); // Imprime el valor formateado

Es importante notar que una aserción de tipo no realiza ninguna conversión de datos en tiempo de ejecución. Solo cambia la forma en que TypeScript considera el tipo de la variable durante la compilación.

const numberValue = 42; // Número original

const numberAssertionAsString = numberValue as unknown as string; // Aserción (NO conversión)
// Esto solo le dice a TypeScript que trate 'numberValue' como si fuera un string.
// El valor 'numberValue' sigue siendo el número 42 en JavaScript.

console.log(typeof numberValue); // typeof original (number)
console.log(typeof numberAssertionAsString); // typeof después de aserción (sigue siendo number en JS!)
// console.log(numberAssertionAsString.length); // Esto causaría error en ejecución al ser un number

// Para una conversión real, usarías funciones de JS
const numberConversionToString = String(numberValue); // Conversión REAL de JS
console.log(typeof numberConversionToString); // typeof después de conversión (string)
console.log(numberConversionToString.length); // Longitud correcta

Cuándo se usan comúnmente las aserciones:

  • Cuando trabajas con variables de tipo any o unknown.
  • Al interactuar con el DOM (Document Object Model), donde TypeScript a veces infiere un tipo genérico (Element) y tú sabes que es uno más específico (HTMLButtonElement).
  • Al recibir datos de fuentes externas (APIs) donde la estructura de datos podría no estar perfectamente tipada.
// Ejemplo con el DOM
// TypeScript podría inferir que 'myButtonElement' es solo un 'Element' o 'null'
const myButtonElement = document.getElementById('my-button') as HTMLButtonElement | null; // Usamos aserción o null

// Usamos una aserción para decir que, si no es null, es definitivamente un HTMLButtonElement
if (myButtonElement !== null) {
  const buttonHtmlElement = myButtonElement as HTMLButtonElement; // Aserción a tipo más específico
  // Ahora TypeScript sabe que 'buttonHtmlElement' es un HTMLButtonElement
  // y permite acceder a propiedades específicas de botones
  buttonHtmlElement.disabled = true;
}

// O de forma más directa si estás seguro de que el elemento existe:
const myTextInputElement = document.getElementById('my-input') as HTMLInputElement; // Aserción directa
console.log(myTextInputElement.value); // Acceso seguro a la propiedad .value

Precaución con las aserciones: Las aserciones debilitan la seguridad de tipos de TypeScript. Si le dices al compilador que un valor es de un tipo X, pero en tiempo de ejecución es de un tipo Y incompatible, podrías encontrarte con errores inesperados (como TypeError en JavaScript). Úsalas solo cuando estés seguro del tipo y no haya una forma más segura de lograrlo.

Guardas de Tipo (typeof, instanceof)

Las guardas de tipo son expresiones que, cuando se evalúan en un bloque condicional (como if), informan a TypeScript sobre un tipo más específico de una variable dentro de ese bloque. A diferencia de las aserciones, las guardas implican comprobaciones en tiempo de ejecución y permiten a TypeScript estrechar (narrow) el tipo automáticamente.

Guarda de Tipo typeof

La guarda typeof es ideal para determinar el tipo de primitivos (string, number, boolean, symbol, bigint, undefined, object, function).

function processInput(input: string | number | undefined | null): void {
  // Antes de la comprobación, 'input' puede ser varios tipos.
  console.log(typeof input); // Puede ser 'string', 'number', 'undefined', 'object' (para null)

  if (typeof input === 'string') {
    // Dentro de este bloque, TypeScript sabe que 'input' es definitivamente un string.
    console.log(`Is a string: ${input.toUpperCase()}`); // Acceso seguro a métodos de string
  } else if (typeof input === 'number') {
    // Dentro de este bloque, TypeScript sabe que 'input' es definitivamente un number.
    console.log(`Is a number: ${input.toFixed(2)}`); // Acceso seguro a métodos de number
  } else if (typeof input === 'undefined') {
    console.log("The value is undefined."); // Mensaje para undefined
  } else if (input === null) { // typeof null es 'object', se necesita comprobación directa
    console.log("The value is null."); // Mensaje para null
  }
  // Fuera de los bloques if, 'input' vuelve a ser la unión original.
}

processInput("Hello"); // Probar con string
processInput(123.456); // Probar con number
processInput(undefined); // Probar con undefined
processInput(null); // Probar con null

Dentro de cada bloque if, TypeScript "estrecha" el tipo de input basándose en la condición evaluada por typeof

Guarda de Tipo instanceof

La guarda instanceof se utiliza para comprobar si un objeto es una instancia de una clase específica o un constructor. Es útil para refinar tipos de objetos.

class Dog {
  bark() { console.log("Woof!"); } // Método ladrar
}

class Cat {
  meow() { console.log("Meow!"); } // Método maullar
}

type Pet = Dog | Cat; // Alias para la unión de clases

function makeSound(pet: Pet): void {
  // Antes de la guarda, 'pet' es Dog | Cat.
  // No puedes llamar directamente a .bark() o .meow() aquí.

  if (pet instanceof Dog) {
    // Dentro de este bloque, TypeScript sabe que 'pet' es definitivamente un Dog.
    pet.bark(); // Acceso seguro al método de Dog
  } else if (pet instanceof Cat) {
    // Dentro de este bloque, TypeScript sabe que 'pet' es definitivamente un Cat.
    pet.meow(); // Acceso seguro al método de Cat
  }
}

const myDog = new Dog(); // Crear instancia de Dog
const myCat = new Cat(); // Crear instancia de Cat

makeSound(myDog); // Llamar con Dog
makeSound(myCat); // Llamar con Cat

Aserciones vs. Guardas de Tipo: ¿Cuándo usar cuál?

  • Guardas de Tipo (typeof, instanceof): Son la opción preferible y más segura cuando es posible utilizarlas. Realizan comprobaciones en tiempo de ejecución y permiten a TypeScript inferir tipos automáticamente dentro de bloques de código, manteniendo la seguridad de tipos. Úsalas siempre que puedas determinar el tipo basado en el valor o la estructura en tiempo de ejecución.
  • Aserciones de Tipo (as): Úsalas solo cuando estés seguro del tipo y las guardas de tipo no sean suficientes (por ejemplo, con any o unknown cuando no puedes hacer una comprobación de typeof/instanceof o estás interactuando con APIs externas). Son una forma de "forzar" un tipo para el compilador basándose en tu conocimiento como desarrollador, pero no ofrecen protección en tiempo de ejecución.

En resumen: los alias de tipos (type) te ayudan a organizar y reutilizar tus definiciones de tipos. Las aserciones de tipo (as) te permiten guiar al compilador cuando tienes más información. Las guardas de tipo (typeof, instanceof) son una forma más segura y automática de refinar tipos en tiempo de ejecución dentro de tu lógica condicional. Combinar estas herramientas te permitirá escribir código TypeScript más robusto, legible y seguro.

Aprende TypeScript online

Otros ejercicios de programación de TypeScript

Evalúa tus conocimientos de esta lección Type aliases y aserciones de tipo con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Funciones

TypeScript
Test

Reto composición de funciones

TypeScript
Código

Reto tipos especiales

TypeScript
Código

Reto tipos genéricos

TypeScript
Código

Módulos

TypeScript
Test

Polimorfismo

TypeScript
Código

Funciones TypeScript

TypeScript
Código

Interfaces

TypeScript
Puzzle

Funciones puras

TypeScript
Puzzle

Reto namespaces

TypeScript
Código

Funciones flecha

TypeScript
Puzzle

Polimorfismo

TypeScript
Test

Operadores

TypeScript
Test

Conversor de unidades

TypeScript
Proyecto

Funciones flecha

TypeScript
Test

Control de flujo

TypeScript
Código

Herencia

TypeScript
Puzzle

Clases

TypeScript
Puzzle

Proyecto validación de tipado

TypeScript
Proyecto

Clases y objetos

TypeScript
Código

Encapsulación

TypeScript
Test

Herencia

TypeScript
Test

Proyecto sistema de votación

TypeScript
Proyecto

Reto genéricos con clases

TypeScript
Código

Inmutabilidad

TypeScript
Puzzle

Interfaces

TypeScript
Test

Funciones de alto orden

TypeScript
Test

Reto map y filter

TypeScript
Código

Control de flujo

TypeScript
Test

Interfaces

TypeScript
Código

Reto funciones orden superior

TypeScript
Código

Herencia y clases abstractas

TypeScript
Código

Reto tipos mapped

TypeScript
Código

Herencia de clases

TypeScript
Código

Reto funciones puras

TypeScript
Código

Variables y constantes

TypeScript
Puzzle

Introducción a TypeScript

TypeScript
Test

Reto testing unitario

TypeScript
Código

Funciones de primera clase

TypeScript
Puzzle

Clases

TypeScript
Test

OOP y CRUD en TypeScript

TypeScript
Proyecto

Interfaces y su implementación

TypeScript
Código

Tipos genéricos

TypeScript
Test

Namespaces

TypeScript
Test

Operadores y expresiones

TypeScript
Código

Proyecto generador de contraseñas

TypeScript
Proyecto

Reto unión e intersección

TypeScript
Código

Encapsulación

TypeScript
Puzzle

Tipos de unión e intersección

TypeScript
Test

Tipos de unión e intersección

TypeScript
Puzzle

Reto hola mundo en TS

TypeScript
Código

Variables y constantes

TypeScript
Código

Funciones puras

TypeScript
Test

Control de flujo

TypeScript
Código

Introducción a TypeScript

TypeScript
Código

Resolución de módulos

TypeScript
Test

Control de flujo

TypeScript
Puzzle

Reto tipos de utilidad

TypeScript
Código

Reto tipos literales y condicionales

TypeScript
Código

Reto exportar e importar

TypeScript
Código

Propiedades y métodos

TypeScript
Código

Tipos de utilidad

TypeScript
Test

Clases y objetos

TypeScript
Código

Tipos de datos, variables y constantes

TypeScript
Código

Proyecto Minigestor de tareas

TypeScript
Proyecto

Operadores

TypeScript
Puzzle

Funciones flecha y contexto

TypeScript
Código

Proyecto Inventario de productos

TypeScript
Proyecto

Funciones

TypeScript
Puzzle

Reto type aliases

TypeScript
Código

Funciones de alto orden

TypeScript
Puzzle

Funciones y parámetros tipados

TypeScript
Código

Tipos literales

TypeScript
Puzzle

Reto enums

TypeScript
Código

Tipos de utilidad

TypeScript
Puzzle

Modificadores de acceso y encapsulación

TypeScript
Código

Polimorfismo

TypeScript
Puzzle

Tipos genéricos

TypeScript
Puzzle

Reto módulos

TypeScript
Código

Tipos literales

TypeScript
Test

Inmutabilidad

TypeScript
Test

Proyecto Generator de datos

TypeScript
Proyecto

Variables y constantes

TypeScript
Test

Funciones de primera clase

TypeScript
Test

Todas las lecciones de TypeScript

Accede a todas las lecciones de TypeScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Typescript

TypeScript

Introducción Y Entorno

Instalación Y Configuración De Typescript

TypeScript

Introducción Y Entorno

Tipos De Datos, Variables Y Constantes

TypeScript

Sintaxis

Operadores Y Expresiones

TypeScript

Sintaxis

Control De Flujo

TypeScript

Sintaxis

Funciones Y Parámetros Tipados

TypeScript

Sintaxis

Funciones Flecha Y Contexto

TypeScript

Sintaxis

Enums

TypeScript

Sintaxis

Type Aliases Y Aserciones De Tipo

TypeScript

Sintaxis

Clases Y Objetos

TypeScript

Programación Orientada A Objetos

Interfaces Y Su Implementación

TypeScript

Programación Orientada A Objetos

Modificadores De Acceso Y Encapsulación

TypeScript

Programación Orientada A Objetos

Herencia Y Clases Abstractas

TypeScript

Programación Orientada A Objetos

Polimorfismo

TypeScript

Programación Orientada A Objetos

Decoradores Básicos

TypeScript

Programación Orientada A Objetos

Propiedades Y Métodos

TypeScript

Programación Orientada A Objetos

Inmutabilidad

TypeScript

Programación Funcional

Funciones Puras Y Efectos Secundarios

TypeScript

Programación Funcional

Funciones De Primera Clase

TypeScript

Programación Funcional

Funciones De Alto Orden

TypeScript

Programación Funcional

Conceptos Básicos E Inmutabilidad

TypeScript

Programación Funcional

Funciones De Primera Clase Y Orden Superior

TypeScript

Programación Funcional

Composición De Funciones

TypeScript

Programación Funcional

Métodos Funcionales De Arrays (Map, Filter, Reduce)

TypeScript

Programación Funcional

Tipos Literales Y Tipos Condicionales

TypeScript

Tipos Intermedios Y Avanzados

Tipos Genéricos Básicos

TypeScript

Tipos Intermedios Y Avanzados

Tipos De Unión E Intersección

TypeScript

Tipos Intermedios Y Avanzados

Tipos De Utilidad (Partial, Required, Pick, Etc)

TypeScript

Tipos Intermedios Y Avanzados

Unknown, Never Y Tipos Especiales

TypeScript

Tipos Intermedios Y Avanzados

Tipos Mapped

TypeScript

Tipos Intermedios Y Avanzados

Genéricos Con Clases E Interfaces

TypeScript

Tipos Intermedios Y Avanzados

Módulos

TypeScript

Namespaces Y Módulos

Namespaces

TypeScript

Namespaces Y Módulos

Resolución De Módulos

TypeScript

Namespaces Y Módulos

Exportación E Importación De Módulos

TypeScript

Namespaces Y Módulos

Introducción A Módulos

TypeScript

Namespaces Y Módulos

Testing Unitario En Typescript

TypeScript

Testing

Accede GRATIS a TypeScript y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Crear alias de tipo para diferentes estructuras con type.
  • Aplicar aserciones de tipo (as) para ayudar al compilador.
  • Utilizar guardas de tipo como typeof e instanceof.
  • Comprender la diferencia entre aserciones y guardas.
  • Mejorar la claridad y seguridad del código con alias y guardas.