Programación Orientada a Objetos en TypeScript: Guía Completa
La Programación Orientada a Objetos (POO) es un paradigma fundamental en el desarrollo de software, que organiza el código en torno a objetos y relaciones entre ellos. Gracias a POO, es posible construir aplicaciones más escalables, mantenibles y fáciles de entender.
En este tutorial, exploraremos cómo aplicar POO en TypeScript, un lenguaje de tipado fuerte que facilita la implementación de conceptos como encapsulamiento, herencia y abstracción.
Con estas bases, podrás escribir código más estructurado y mejorar la reutilización en tus proyectos TypeScript, optimizando tu trabajo en aplicaciones de cualquier escala.
¿Qué necesito saber para poder seguir este tutorial?
Para seguir este tutorial, es importante que tengas conocimientos previos de Programación Orientada a Objetos y que tengas claros conceptos como encapsulamiento, herencia y abstracción. Si aún no los tienes, te sugiero adquirir primero esos conocimientos y luego regresar para continuar.
Si es tu primera vez con TypeScript, te recomiendo que antes te pases por este tutorial. Aprende TypeScript Desde Cero: Qué es, instalación y tipado.
Encapsulamiento con TypeScript
Al igual que en otros lenguajes de programación, en TypeScript disponemos de los siguientes controles de acceso a atributos y métodos:
public
: Permite el acceso desde cualquier parte del programa. Los miembrospublic
pueden ser accedidos desde cualquier clase o módulo que importe esta clase.protected
: Permite el acceso solo desde la propia clase y sus subclases. Los miembrosprotected
no son accesibles desde fuera de la clase.private
: Limita el acceso exclusivamente a la clase donde se define. Los miembrosprivate
no pueden ser accedidos desde clases externas ni desde subclases; solo pueden ser usados dentro de la clase donde se declararon.static
: El modificadorstatic
no es un nivel de acceso en sí, sino una indicación de que el miembro pertenece a la clase en lugar de a las instancias individuales.
Constructor y atributos en TypeScript
Para declarar una clase en TypeScript, solo necesitas utilizar la palabra reservada class
y el nombre de la clase seguida de las llaves {}
. Ejemplo:
export class Developer {
private name: string = '';
constructor() {}
}
En este ejemplo he declarado un atributo llamado name
que será privado. TypeScript nos obliga a darle un valor por defecto, por lo que lo he inicializado a un string
vacío. Si queremos evitar esto, tenemos dos opciones. La primera es declararlo como opcional como ya vimos en el tutorial anterior utilizando el operador ?
.
export class Developer {
private name?: string;
constructor() {}
}
Otra opción es declarar el atributo dentro del constructor, de esta forma, al crear una instancia de la clase, deberemos enviar el parámetro:
export class Developer {
constructor(private name: string) {}
}
Interfaces en TypeScript
También es posible definir interfaces para implementarlas posteriormente en nuestras clases. Por convención, el nombre de una interfaz suele comenzar con una 'I' mayúscula.
export interface IEmployee {
name: string;
}
Para implementar nuestra interfaz en una clase, utilizamos la palabra reservada implements
:
import { IEmployee } from "./IEmployee";
export class Developer implements IEmployee {
name: string = '';
constructor(name: string) {}
}
Herencia en TypeScript
La herencia es muy similar a otros lenguajes de programación. Primero declaramos la clase padre:
export class Employee {
constructor(protected name: string, protected salary: number) {}
}
Después, solo necesitamos exportarla a la clase hija y extender de ella utilizando la palabra reservada extends
.
import { Employee } from "./Employee";
export class Developer extends Employee {
constructor(protected name: string, protected salary: number, private knownProgrammingLanguaes: string[]) {
super(name, salary)
}
}
Como puedes observar, en este ejemplo he modificado el constructor añadiendo un nuevo parámetro y luego utilizo super()
. super()
es una llamada que se usa dentro del constructor de una clase que extiende de otra clase. Esta llamada se utiliza para invocar el constructor de la clase padre y asegurar que la clase hija tenga acceso a las propiedades y métodos heredados correctamente.
Cuando una subclase hereda de otra clase y tiene su propio constructor, es obligatorio llamar a super()
antes de usar this
. Esto permite que el constructor de la clase padre inicialice sus propias propiedades y ejecute cualquier lógica que se haya definido para esa clase antes de que la subclase defina la suya.
Clases genéricas
Las clases genéricas son clases que permiten definir tipos de datos de forma flexible y reutilizable sin especificar el tipo exacto de antemano.
Esto se logra mediante parámetros de tipo, que se representan con letras entre corchetes angulares (<T>
, <U>
, etc.).
Las clases genéricas permiten que el tipo de datos se determine en el momento en que se instancian, por lo que en ese momento es cuando determinamos que tipo de dato va a utilizar.
Mejorando el ejemplo anterior, podemos añadir en la clase Developer
el tipo de dato y enviarlo como se explicó anteriormente para después utilizarlo:
import { Employee } from "./Employee";
export class Developer<T> extends Employee {
constructor(
protected name: string,
protected salary: number,
private knownProgrammingLanguaes: string[],
private typeDev: T
) {
super(name, salary)
}
}
type typeDevs = 'team lead' | 'senior' | 'junior'
const dev = new Developer<typeDevs>('Alber', 1000, ['php', 'node.js', 'python'], 'senior')
Con esto cerramos este tutorial. Te dejo el enlace al repositorio y espero verte de nuevo pronto por aquí porque seguiré añadiendo tutoriales de esta temática 💪.
Espero que este post te ayude y como siempre, te recomiendo seguirme en Twitter para estar al tanto de los nuevo contenido. Ahora también puedes seguirme en Instagram donde estoy subiendo tips, tutoriales en vídeo e información sobre herramientas para developers.
Por último os dejo mi guía para aprender a trabajar con APIs donde explico todo el funcionamiento de una API, el protocolo HTTP y veremos como construir una API con arquitectura REST.
Nos leemos 👋.