Skip to content

Lección 86 — Opcionales, Readonly e Index Signatures

TypeScript ofrece tres herramientas fundamentales para refinar cómo se accede y modifica las propiedades de un objeto: opcionales, readonly e index signatures.

Ya las vimos en lecciones anteriores. Marcan una propiedad que puede estar presente o no:

interface Config {
url: string;
puerto?: number; // opcional
timeout?: number; // opcional
}

Una propiedad readonly solo puede leerse, no reasignarse después de la inicialización:

interface Punto {
readonly x: number;
readonly y: number;
}
const p: Punto = { x: 10, y: 20 };
// p.x = 15; ❌ Error: Cannot assign to 'x' because it is a read-only property
let numeros: ReadonlyArray<number> = [1, 2, 3];
// numeros.push(4); ❌ Error
// numeros[0] = 10; ❌ Error
let tupla: readonly [string, number] = ['Ana', 30];
// tupla[0] = 'Luis'; ❌ Error

Permiten definir objetos con propiedades dinámicas donde solo conoces el tipo de la clave y el valor:

interface Diccionario {
[clave: string]: string;
}
const traducciones: Diccionario = {
hola: 'hello',
adios: 'goodbye'
};

Puedes mezclar propiedades fijas con index signatures:

interface UsuarioDinamico {
nombre: string;
edad: number;
[extra: string]: unknown; // propiedades adicionales
}
const usuario: UsuarioDinamico = {
nombre: 'Ana',
edad: 30,
ciudad: 'Madrid', // ✅ permitido
pais: 'España' // ✅ permitido
};
// Objeto de configuración con opcionales y readonly
interface ConfiguracionApp {
readonly nombreApp: string;
readonly version: string;
puerto?: number;
debug?: boolean;
[key: string]: unknown;
}
const config: ConfiguracionApp = {
nombreApp: 'MiApp',
version: '1.0.0',
puerto: 3000,
debug: true,
dbHost: 'localhost', // propiedad dinámica
dbPort: 5432 // propiedad dinámica
};
// No se puede reasignar readonly
// config.nombreApp = 'OtraApp'; ❌
// ReadonlyArray
const inmovible: ReadonlyArray<string> = ['a', 'b', 'c'];
// inmovible[0] = 'z'; ❌
// Index signature para caché
interface Cache {
[url: string]: {
datos: unknown;
timestamp: number;
};
}
const cache: Cache = {
'/api/users': { datos: [], timestamp: Date.now() },
'/api/products': { datos: [], timestamp: Date.now() }
};

Crea una interfaz Inventario con:

  • Una propiedad readonly id: number.
  • Una propiedad opcional nombre: string.
  • Una index signature [codigo: string]: number para almacenar cantidades de productos.

Crea un objeto inventario, asigna algunos productos con cantidades, e intenta modificar el id para ver el error.

Cuando combinas propiedades fijas con index signatures, la index signature debe ser compatible con todas las propiedades fijas. Por ejemplo, si tienes prop: string, la index signature debe ser [key: string]: string (no number).

Usa readonly en propiedades que representan identificadores o constantes de configuración que no deben cambiar después de la creación. Ayuda a prevenir mutaciones accidentales.