Interfaces: usándolas con clases

Como en otros lenguajes de programación orientados a objetos, las interfaces pueden utilizarse para fabricar un contrato o una especificación con operaciones que debe tener una clase. En este vídeo os enseño cómo implementar interfaces en clases y cómo usarlos para fabricar abstracciones.

Las interfaces en TypeScript no solo sirven para definir contratos para objetos simples, sino que también pueden ser implementadas por clases completas, lo que nos permite crear estructuras más robustas y flexibles en nuestros programas. Cuando una clase implementa una interfaz, está comprometiéndose a cumplir con un conjunto específico de propiedades y métodos, lo que facilita que diferentes clases compartan comportamientos comunes y puedan ser tratadas de manera uniforme.

Imaginemos que definimos una interfaz llamada Shape para representar formas geométricas. Esta interfaz podría incluir propiedades como el número de lados, que sería de solo lectura porque cambiarlo implicaría que la forma es otra distinta. Además, incluiría métodos para calcular el área y el perímetro de la figura. Así, cualquier clase que implemente Shape deberá proporcionar estas propiedades y métodos, garantizando que se comporta como una forma geométrica.

interface Shape {
  readonly sides: number;
  area(): number;
  perimeter(): number;
}

Ahora, si queremos representar un rectángulo, podemos crear una clase Rectangle que implemente esta interfaz. Para simplificar la declaración de propiedades, podemos aprovechar una característica de TypeScript que permite definir y asignar propiedades directamente en el constructor usando modificadores de acceso como readonly o private. Esto nos ahorra tener que declarar las propiedades por separado.

class Rectangle implements Shape {
  constructor(
    public readonly width: number,
    public readonly height: number
  ) {}

  get sides(): number {
    return 4;
  }

  area(): number {
    return this.width * this.height;
  }

  perimeter(): number {
    return 2 * this.width + 2 * this.height;
  }
}

Al implementar la interfaz Shape, nuestra clase Rectangle se convierte en un tipo que puede ser utilizado donde se espere un Shape. Por ejemplo, si tenemos una función process que acepta un objeto de tipo Shape, podremos pasarle un Rectangle sin problemas, ya que cumple con el contrato definido por la interfaz.

function process(shape: Shape) {
  console.log(`Sides: ${shape.sides}`);
  console.log(`Area: ${shape.area()}`);
  console.log(`Perimeter: ${shape.perimeter()}`);
}

const rect = new Rectangle(10, 5);
process(rect);

Dentro de la función process, solo podemos acceder a las propiedades y métodos definidos en la interfaz Shape, lo que limita el conocimiento que tenemos sobre el objeto y promueve la abstracción. No podemos acceder a propiedades específicas de Rectangle como width o height, ya que la función solo sabe que está trabajando con un Shape. Esto es un ejemplo claro de encapsulación y abstracción, principios fundamentales de la programación orientada a objetos que nos ayudan a escribir código más limpio y mantenible.

Además, una clase puede implementar múltiples interfaces separándolas por comas, lo que le permite adoptar múltiples roles o comportamientos según sea necesario. Esto hace que las instancias de una clase sean agentes múltiples, capaces de adaptarse a diferentes contextos sin perder su identidad principal.

Por último, aunque en este ejemplo hemos trabajado con una interfaz sencilla y una clase concreta, las interfaces también pueden especializarse y combinarse con la herencia de clases para crear jerarquías más complejas y flexibles. Esto abre un abanico de posibilidades para diseñar sistemas que sean tanto robustos como fáciles de extender y mantener.

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