
TypeScript: Clases, herencia y patrones de diseño
- Dacadev
- Programación
- 19 de junio de 2026
Tabla de Contenido
Note
Sexto artículo de la serie sobre TypeScript. Recorreremos las clases: herencia, modificadores de acceso, clases abstractas, super, getters/setters, miembros estáticos, tipado estructural y los patrones de diseño que habilitan.
Las clases en TypeScript parten de la sintaxis de JavaScript y la enriquecen con modificadores de acceso, clases abstractas y tipado estructural. El resultado es un modelo de orientación a objetos cercano al de lenguajes como C++ o Java, pero que compila a JavaScript estándar. Analicemos sus capacidades.
Clases y herencia
La declaración usa class y la herencia se establece con extends:
class Piece {}
class King extends Piece {}
class Queen extends Piece {}
class Bishop extends Piece {}
Podemos restringir los atributos a valores concretos combinando clases con tipos literales:
type Color = 'Black' | 'White'
type File = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H'
type Rank = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
class Position {
constructor(
private file: File,
private rank: Rank
) {}
}
Declarar los parámetros del constructor con un modificador (private file: File) es un atajo: TypeScript crea y asigna la propiedad automáticamente, evitando el habitual this.file = file.
Modificadores de acceso
TypeScript define tres niveles de visibilidad para atributos y métodos:
public: accesible desde cualquier lugar. Es el nivel por defecto.protected: accesible desde la propia clase y sus subclases.private: accesible únicamente desde la propia clase.
class Avenger {
constructor(
private name: string,
public team: string,
public realName?: string
) {}
public bio() {
return `${this.name} ${this.team}`
}
private bioInterno() {
return `${this.realName} ${this.team}`
}
}
Warning
private y protected solo aplican en tiempo de compilación. El JavaScript emitido no impide el acceso en runtime; para privacidad real en ejecución usa los campos privados nativos de JavaScript (#campo).
Clases abstractas
Una clase abstract define una plantilla que no puede instanciarse, pero sirve de esqueleto para sus subclases. Puede declarar miembros concretos y miembros abstract que las subclases están obligadas a implementar:
abstract class Mutante {
constructor(
public name: string,
public realName: string
) {}
}
class Xmen extends Mutante {
public saveWorld() {
return 'Mundo salvado'
}
}
class Villano extends Mutante {
public conquistWorld() {
return 'Mundo conquistado'
}
}
const wolverine = new Xmen('Wolverine', 'Logan')
const magneto = new Villano('Magneto', 'Magnus')
Una ventaja adicional: una función puede aceptar cualquier objeto que herede de la clase abstracta, lo que habilita el polimorfismo:
const printName = (character: Mutante) => {
console.log(character.name)
}
printName(wolverine)
printName(magneto)
super: invocar a la clase padre
Cuando una subclase sobrescribe un método del padre, puede invocar la versión original con super.metodo(). Si la subclase define un constructor, debe llamar a super() para inicializar correctamente la cadena de herencia:
class Xmen extends Avenger {
constructor(name: string, realName: string, public isMutant: boolean) {
super(name, realName)
}
public getFullNameDesdeXmen() {
return super.getFullName()
}
}
Getters y setters
Los accessors exponen métodos que se comportan sintácticamente como atributos, facilitando la lectura y asignación controladas:
class Xmen extends Avenger {
get fullName() {
return `${this.name} - ${this.realName}`
}
set fullName(name: string) {
this.realName = name
}
}
const wolverine = new Xmen('Wolverine', 'Logan', true)
console.log(wolverine.fullName) // se lee como atributo
wolverine.fullName = 'David' // se asigna como atributo
Miembros estáticos
Los miembros static pertenecen a la clase, no a sus instancias:
class Avenger {
static avgAge: number = 35
static getAvgAge() {
return Avenger.avgAge
}
}
console.log(Avenger.avgAge) // se accede vía la clase
this como tipo de retorno
Cuando un método retorna la propia instancia, su tipo de retorno es this. Esto es la base del encadenamiento de métodos (method chaining):
class Set {
add(value: number): this {
// ...
return this
}
}
Tipado estructural
TypeScript verifica las clases por estructura, no por nombre. Dos tipos compatibles en forma son intercambiables, con una salvedad: los miembros private rompen la compatibilidad estructural:
class A {
private x = 1
}
class B extends A {}
function f(a: A) {}
f(new A()) // OK
f(new B()) // OK
f({ x: 1 }) // Error TS2345: 'x' es private en 'A' pero no en '{x: number}'.
Constructor privado
Un constructor private impide instanciar la clase desde fuera, lo que permite controlar su creación. Es la base del patrón singleton:
class Apocalipsis {
private static instance: Apocalipsis
private constructor(public name: string) {}
static getInstance(): Apocalipsis {
if (!Apocalipsis.instance) {
Apocalipsis.instance = new Apocalipsis('Soy Apocalipsis... el único')
}
return Apocalipsis.instance
}
}
const apocalipsis = Apocalipsis.getInstance()
Patrones de diseño habilitados
Factory Pattern
Centraliza la creación de objetos detrás de una función que decide la clase concreta:
type Shoe = { purpose: string }
class BalletFlat implements Shoe { purpose = 'dancing' }
class Boot implements Shoe { purpose = 'woodcutting' }
class Sneaker implements Shoe { purpose = 'walking' }
let Shoe = {
create(type: 'balletFlat' | 'boot' | 'sneaker'): Shoe {
switch (type) {
case 'balletFlat': return new BalletFlat()
case 'boot': return new Boot()
case 'sneaker': return new Sneaker()
}
}
}
Builder Pattern
Construye un objeto paso a paso mediante métodos que retornan this, habilitando una API fluida:
class RequestBuilder {
private data: object | null = null
private method: 'get' | 'post' | null = null
private url: string | null = null
setMethod(method: 'get' | 'post'): this {
this.method = method
return this
}
setData(data: object): this {
this.data = data
return this
}
setURL(url: string): this {
this.url = url
return this
}
send() {
// ...
}
}
new RequestBuilder().setURL('/api').setMethod('post').setData({}).send()
Conclusión
Las clases de TypeScript ofrecen un modelo de orientación a objetos completo: herencia, modificadores de acceso, clases abstractas para polimorfismo, accessors, miembros estáticos y un tipado estructural con la salvedad de los miembros privados. Estas piezas son el fundamento de patrones de diseño como Factory, Builder y Singleton.
En el siguiente artículo abordaremos los genéricos, la herramienta para escribir código reutilizable sin sacrificar la seguridad de tipos.


