Clases: modificador readonly

Con el modificador readonly podemos hacer que un atributo pueda ser constante. Una vez se le declara un valor ya no puede ser modificado, ni dentro ni fuera de la clase.

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.

Lista de reproducción
  1. 1
    Temporada 1
    5 minutos
  2. 2
    ¿Qué es TypeScript?
    11 minutos
  3. 3
    Instalando TypeScript
    8 minutos
  4. 4
    Compilando un Hola Mundo sencillo
    7 minutos
  5. 5
    Hola Mundo pero con tipos
    10 minutos
  6. 6
    Tipos: tipos primitivos
    12 minutos
  7. 7
    Tipos: tipos especiales (any, null, ...)
    10 minutos
  8. 8
    Tipos: arrays y tuplas
    11 minutos
  9. 9
    Tipos: objetos
    7 minutos
  10. 10
    Funciones: lo básico
    9 minutos
  11. 11
    Funciones: tipando funciones
    9 minutos
  12. 12
    Clases: introducción a las clases
    9 minutos
  13. 13
    Clases: creando una clase
    10 minutos
  14. 14
    Clases: modificador private
    8 minutos
  15. 15
    Clases: modificador readonly
    3 minutos
  16. 16
    Clases: Atributos virtuales con getters y setters
    10 minutos
  17. 17
    Clases: herencia
    9 minutos
  18. 18
    Clases: modificadores abstract y protected
    8 minutos
  19. 19
    Tipos alias
    6 minutos
  20. 20
    Tipos literales
    5 minutos
  21. 21
    Uniones de tipos
    7 minutos
  22. 22
    Uniones discriminantes
    7 minutos
  23. 23
    Intersecciones de tipos
    5 minutos
  24. 24
    Interfaces: introducción
    7 minutos
  25. 25
    Interfaces: modificadores y funciones
    9 minutos
  26. 26
    Interfaces: usándolas con clases
    8 minutos
  27. 27
    Interfaces: herencia de interfaces
    8 minutos
  28. 28
    Interfaces: interfaces indizadas
    5 minutos
  29. 29
    Interfaces: funciones y tipos híbridos
    5 minutos
  30. 30
    ¿Qué diferencia hay entre interfaces y tipos? (2020)
    8 minutos
  31. 31
    Casteos con as
    6 minutos
  32. 32
    instanceof y las guardas
    9 minutos
  33. 33
    Tipos enumerados
    8 minutos
  34. 34
    Valores avanzados para enumerados
    7 minutos
  35. 35
    Enumerados con valores computados
    6 minutos
  36. 36
    Genéricos en tipos
    8 minutos
  37. 37
    Múltiples genéricos y buenas prácticas
    5 minutos
  38. 38
    Genéricos en funciones
    8 minutos
  39. 39
    Genéricos con restricciones
    6 minutos
  40. 40
    Tipos de utilidad
    3 minutos
  41. 41
    Exportando módulos
    9 minutos
  42. 42
    Importando módulos
    7 minutos
  43. 43
    Export default e import asterisco
    6 minutos
  44. 44
    tsconfig
    7 minutos
  45. 45
    Módulos desde NPM
    7 minutos
  46. 46
    Arroba types y los .d.ts
    8 minutos
  47. 47
    Ejemplo (1): creando una API REST simple en TypeScript
    11 minutos
  48. 48
    Ejemplo (2): montando un servidor Express
    8 minutos
  49. 49
    Ejemplo (3): haciendo las funciones de control de datos
    11 minutos
  50. 50
    Ejemplo (4): conectando todas las piezas
    7 minutos