Const assertions y tipos inmutables

Intermedio
TypeScript
TypeScript
Actualizado: 04/05/2026

Diagrama: tutorial-typescript-const-assertions

Tipos literales vs tipos amplios

Por defecto, TypeScript infiere el tipo más amplio posible para las variables. Cuando escribes let mensaje = "hola", TypeScript infiere string, no "hola". Esto tiene sentido para variables reasignables, pero a veces necesitas que el compilador trate un valor como su tipo más específico.

let mensaje = "hola";       // tipo: string
const saludo = "hola";      // tipo: "hola" (literal)

let numero = 42;            // tipo: number
const respuesta = 42;       // tipo: 42 (literal)

Con const a nivel de variable TypeScript ya infiere el tipo literal. Pero para arrays y objetos, incluso con const, el tipo sigue siendo amplio:

const colores = ["rojo", "verde", "azul"]; // tipo: string[] (¡no un tuple literal!)
const punto = { x: 10, y: 20 };           // tipo: { x: number; y: number } (¡no literales!)

La sintaxis as const

La const assertion (as const) le indica a TypeScript que infiera el tipo más estrecho y de solo lectura posible para toda la expresión:

const colores = ["rojo", "verde", "azul"] as const;
// tipo: readonly ["rojo", "verde", "azul"]

const punto = { x: 10, y: 20 } as const;
// tipo: { readonly x: 10; readonly y: 20 }

Cada valor se convierte en su tipo literal, y todas las propiedades y elementos del array se marcan como readonly.

Arrays de constantes y tipos de unión

Uno de los usos más potentes de as const es derivar tipos de unión a partir de arrays de constantes, eliminando la necesidad de duplicar los valores en un tipo separado:

const ROLES = ["admin", "editor", "lector", "invitado"] as const;

// Derivar el tipo de unión automáticamente:
type Rol = typeof ROLES[number]; // "admin" | "editor" | "lector" | "invitado"

// Ahora puedes usar Rol como tipo en otros lugares:
function asignarRol(usuario: string, rol: Rol): void {
    console.log(`${usuario} → ${rol}`);
}

asignarRol("Ana", "admin");    // ✓
asignarRol("Luis", "gestor");  // ✗ Error: Argument of type '"gestor"' is not assignable

Este patrón es especialmente valioso porque la fuente de verdad es el array. Si añades un elemento al array, el tipo Rol se actualiza automáticamente sin tocar la definición de tipo.

Objetos de configuración con as const

Los objetos de configuración se benefician enormemente de as const, garantizando que ningún código externo pueda modificar los valores y que TypeScript los trate como literales:

const CONFIG = {
    API_URL: "https://api.ejemplo.com",
    TIMEOUT: 5000,
    REINTENTOS: 3,
    ENTORNOS: ["desarrollo", "staging", "produccion"]
} as const;

// Tipos inferidos:
// CONFIG.API_URL: "https://api.ejemplo.com"
// CONFIG.TIMEOUT: 5000
// CONFIG.REINTENTOS: 3
// CONFIG.ENTORNOS: readonly ["desarrollo", "staging", "produccion"]

type Entorno = typeof CONFIG.ENTORNOS[number]; // "desarrollo" | "staging" | "produccion"

Enums vs as const

Las const assertions con objetos son frecuentemente preferidas sobre los enums en TypeScript moderno, porque generan código JavaScript más simple y no requieren sintaxis especial del lenguaje:

// Con enum (TypeScript específico, genera código JavaScript adicional)
enum DireccionEnum {
    Arriba = "ARRIBA",
    Abajo = "ABAJO",
    Izquierda = "IZQUIERDA",
    Derecha = "DERECHA"
}

// Con as const (sintaxis estándar JavaScript, tipo derivado)
const Direccion = {
    Arriba: "ARRIBA",
    Abajo: "ABAJO",
    Izquierda: "IZQUIERDA",
    Derecha: "DERECHA"
} as const;

type Direccion = typeof Direccion[keyof typeof Direccion];
// "ARRIBA" | "ABAJO" | "IZQUIERDA" | "DERECHA"

Readonly profundo con as const

as const aplica readonly de forma recursiva en objetos anidados:

const arbol = {
    valor: 1,
    izquierda: {
        valor: 2,
        izquierda: null,
        derecha: null
    },
    derecha: {
        valor: 3,
        izquierda: null,
        derecha: null
    }
} as const;

// arbol.valor: 1 (readonly)
// arbol.izquierda.valor: 2 (readonly, aunque es propiedad anidada)
arbol.valor = 5;               // ✗ Error: Cannot assign to 'valor' because it is read-only
arbol.izquierda.valor = 5;     // ✗ Error: Cannot assign to 'valor' because it is read-only

as const en parámetros de función

Puedes aplicar as const directamente al pasar argumentos a funciones, sin necesidad de declarar una constante intermedia:

function moverElemento(elemento: string, posicion: readonly [number, number]): void {
    console.log(`Moviendo ${elemento} a [${posicion[0]}, ${posicion[1]}]`);
}

// Con as const directamente en el argumento:
moverElemento("cuadro", [100, 200] as const);

Limitaciones de as const

as const tiene algunas restricciones a tener en cuenta:

  1. No se puede usar en variables de bloque reasignables: solo tiene efecto real en const (aunque técnicamente es válido con let).
  2. No afecta a variables externas: si el valor proviene de una variable let, no se puede inferir el literal.
  3. Los tipos readonly no son inmutables en tiempo de ejecución: es solo información de tipos, el objeto JavaScript subyacente sigue siendo mutable (a menos que uses Object.freeze()).
let base = "valor";
const obj = { clave: base } as const;
// obj.clave: string (no "valor", porque base podría cambiar)

Combinación con satisfies

La combinación as const satisfies Tipo ofrece lo mejor de ambos mundos: los tipos literales de as const con la validación del contrato de satisfies:

type OpcionesColor = {
    primario: string;
    secundario: string;
    fondo: string;
};

const coloresTema = {
    primario: "#3178c6",
    secundario: "#235a97",
    fondo: "#ffffff"
} as const satisfies OpcionesColor;

// coloresTema.primario: "#3178c6" (literal) ← gracias a as const
// Validado que cumple OpcionesColor ← gracias a satisfies
// Si pones "verdad" en primario, TypeScript lo detecta como error

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en TypeScript

Documentación oficial de TypeScript
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TypeScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de TypeScript

Explora más contenido relacionado con TypeScript y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender la diferencia entre tipos literales y tipos amplios en TypeScript
  • Aplicar as const para inferir tipos literales en lugar de tipos primitivos genéricos
  • Crear arrays readonly y objetos inmutables con as const
  • Derivar tipos de unión a partir de arrays de constantes usando typeof e indexación
  • Combinar const assertions con satisfies para validación y especificidad simultáneas