Skip to content

Lección 87 — Tipos Literales y Const Assertions

Los tipos literales permiten especificar valores exactos como tipos. Las const assertions (as const) convierten un valor mutable en un tipo inmutable y preciso.

Un tipo literal no es solo string o number, sino un valor específico:

type Color = 'rojo' | 'verde' | 'azul';
type Direccion = 'norte' | 'sur' | 'este' | 'oeste';
type Puerto = 3000 | 3001 | 8080;
let miColor: Color = 'rojo'; // ✅
let miColor2: Color = 'amarillo'; // ❌ Error

Los tipos literales suelen combinarse con union types para crear opciones fijas.

Cuando usas as const al final de un valor, TS infiere el tipo más específico posible y marca todo como readonly:

// Sin as const
let colores = ['rojo', 'verde', 'azul'];
// tipo: string[]
// Con as const
const coloresConst = ['rojo', 'verde', 'azul'] as const;
// tipo: readonly ['rojo', 'verde', 'azul']
  1. Literales en lugar de tipos generales: los valores se convierten en sus tipos literales.
  2. readonly en arrays y objetos: no se pueden modificar.
  3. Anidación profunda: afecta a todas las propiedades anidadas.
const config = {
url: 'https://api.example.com',
puerto: 443,
opciones: {
timeout: 5000,
retries: 3
}
} as const;
// config.url = 'otra'; ❌ readonly
// config.opciones.timeout = 3000; ❌ readonly
// Tipo inferido:
// {
// readonly url: 'https://api.example.com';
// readonly puerto: 443;
// readonly opciones: {
// readonly timeout: 5000;
// readonly retries: 3;
// };
// }
// Tipos literales para una máquina de estados
type EstadoPedido = 'pendiente' | 'confirmado' | 'enviado' | 'entregado' | 'cancelado';
function transicionEstado(actual: EstadoPedido, nuevo: EstadoPedido): EstadoPedido {
if (actual === 'cancelado') {
throw new Error('No se puede cambiar un pedido cancelado');
}
return nuevo;
}
// as const en arrays
const DIAS_LABORABLES = ['lun', 'mar', 'mié', 'jue', 'vie'] as const;
type DiaLaborable = typeof DIAS_LABORABLES[number]; // 'lun' | 'mar' | 'mié' | 'jue' | 'vie'
function esLaborable(dia: string): dia is DiaLaborable {
return DIAS_LABORABLES.includes(dia as DiaLaborable);
}
// as const en objetos
const ROLES = {
ADMIN: 'admin',
EDITOR: 'editor',
VISOR: 'visor'
} as const;
type Rol = typeof ROLES[keyof typeof ROLES]; // 'admin' | 'editor' | 'visor'
function tienePermiso(rol: Rol, accion: string): boolean {
if (rol === ROLES.ADMIN) return true;
if (rol === ROLES.EDITOR) return accion !== 'eliminar';
return accion === 'leer';
}

Define un objeto CONFIG_APP con as const que contenga:

  • nombreApp: 'MiApp'
  • version: '2.0.0'
  • entornos: ['dev', 'staging', 'prod'] como array

Usa typeof y keyof para extraer:

  • El tipo NombreApp (literal)
  • El tipo Entorno (unión de los valores del array)
  • El tipo Version (literal)

as const no convierte el valor en una constante JS (eso ya lo hace const). Lo que hace es cambiar cómo TypeScript infiere el tipo. El valor sigue siendo mutable en runtime si no usas const o medidas adicionales.

Combina as const con typeof para extraer tipos literales de configuraciones y constantes. Es una técnica muy potente para mantener una única fuente de verdad: defines los valores una vez y derivas los tipos automáticamente.