Cuando trabajamos con clases en TypeScript, una de las preocupaciones habituales es cómo proteger los atributos para evitar modificaciones inesperadas que puedan comprometer la integridad de nuestros objetos. En este sentido, TypeScript nos ofrece el modificador readonly, una herramienta muy útil para garantizar que ciertos atributos permanezcan inmutables una vez inicializados.
Para ilustrar esto, retomamos el ejemplo clásico de una clase Rectángulo que tiene atributos públicos ancho y alto. Al ser públicos, estos atributos pueden ser accedidos y modificados desde fuera de la clase sin restricciones. Esto significa que cualquier código cliente puede cambiar el valor de ancho o alto en cualquier momento, lo que puede llevar a inconsistencias, como alterar el área del rectángulo sin control.
Aquí es donde entra en juego readonly. Al declarar un atributo como readonly, le indicamos a TypeScript que ese valor solo puede asignarse una vez, generalmente en el constructor, y que no podrá modificarse posteriormente, ni siquiera desde dentro de la propia clase. Esto es similar a la palabra clave final en otros lenguajes como Java.
Veamos cómo se implementa esto en código:
class Rectangulo {
readonly ancho: number;
readonly alto: number;
constructor(ancho: number, alto: number) {
this.ancho = ancho;
this.alto = alto;
}
area(): number {
return this.ancho * this.alto;
}
}
const R1 = new Rectangulo(10, 15);
console.log(R1.area()); // 150
// Intentar modificar el ancho después de la creación genera error
// R1.ancho = 12; // Error: Cannot assign to 'ancho' because it is a read-only property.
Como se observa, una vez que asignamos los valores en el constructor, cualquier intento de cambiar ancho o alto fuera o dentro de la clase será rechazado por el compilador. Esto nos brinda una capa extra de seguridad y nos ayuda a mantener la consistencia de nuestros objetos.
Además, podemos combinar readonly con el modificador private para restringir aún más el acceso, evitando modificaciones accidentales incluso dentro de la propia clase. Por ejemplo:
class Rectangulo {
private readonly ancho: number;
private readonly alto: number;
constructor(ancho: number, alto: number) {
this.ancho = ancho;
this.alto = alto;
}
area(): number {
return this.ancho * this.alto;
}
}
En este caso, ancho y alto no solo son inmutables, sino que tampoco pueden ser accedidos directamente desde fuera de la clase, reforzando el encapsulamiento.
Es importante destacar que, si queremos que un atributo tenga un valor fijo para todas las instancias, podemos asignarle un valor directamente en la declaración, sin necesidad de hacerlo en el constructor. Sin embargo, si queremos que cada instancia tenga valores diferentes, debemos asignarlos en el constructor, ya que readonly permite la asignación solo en ese momento.
En definitiva, usar readonly nos ayuda a diseñar clases más robustas y seguras, evitando modificaciones no deseadas y facilitando el mantenimiento del código.