Apariencia
📘 Clase 8 — Herencia (extends)
TypeScript · 2026-07-12 · Carpeta:
02-Ejercicios/Herencia⬅️ Volver al índice de clases
🎯 Qué aprendí
- Qué significa extender una clase en TypeScript.
- Cómo usar
extendspara heredar propiedades y métodos. - Cómo crear una clase hija
Empleadoa partir de una clase basePersona. - Para qué sirve
super(...)dentro del constructor. - Cómo sobrescribir métodos heredados.
- Cómo funciona la compilación en cascada cuando un archivo importa a otro.
- Qué archivos
.jsdebes llevar a producción para que todo funcione.
📖 PARTE TEÓRICA
🧱 1. ¿Qué significa extender una clase?
Extender una clase en TypeScript te permite crear una nueva clase que hereda propiedades y métodos de otra sin modificar la original.
Con la palabra reservada extends puedes ampliar una clase base como Persona y construir variantes especializadas como Empleado, sumando nuevas propiedades y comportamientos.
💡 Es una técnica clave para reutilizar código en proyectos orientados a objetos.
🧬 2. ¿Qué hace extends?
La idea es simple: ya tienes una clase Persona que define ciertos datos y comportamientos, y quieres una versión más específica que además tenga su propia lógica.
typescript
export class Empleado extends Persona {
// ...
}extends le dice a TypeScript:
- “esta clase nueva hereda lo de la clase base”
- “no dupliques lo que ya existe”
- “solo agrega lo nuevo”
🧪 ¿Qué hace la palabra clave
extends? Le indica a TypeScript que la nueva clase hereda propiedades y métodos de la clase base.
👤 3. Clase base Persona
La clase base real usada en tu ejercicio fue esta:
typescript
export class Persona {
public name: string;
protected age: number;
private isDeveloper: boolean;
constructor(name: string, age: number, isDeveloper: boolean) {
this.name = name;
this.age = age;
this.isDeveloper = isDeveloper;
}
public saludar(): string {
return `Hola, mi nombre es ${this.name}, tengo ${this.age} años`;
}
protected obtenerEdad(): number {
return this.age;
}
private esDesarrollador(): boolean {
return this.isDeveloper;
}
}Esta clase ya tiene:
- una propiedad pública:
name - una protegida:
age - una privada:
isDeveloper - un método público:
saludar()
🧑💼 4. Clase hija Empleado
Luego creaste una clase Empleado que extiende de Persona:
typescript
import { Persona } from "./clase.js";
export class Empleado extends Persona {
public position: string;
constructor(name: string, age: number, isDeveloper: boolean, puesto: string) {
super(name, age, isDeveloper);
this.position = puesto;
}
public saludar(): string {
return `Hola, trabajo como ${this.position}`;
}
public ObtenerInfo(): string {
return `Hola, mi nombre es ${this.name}, tengo ${this.obtenerEdad()} años y trabajo como ${this.position}`;
}
}Lo importante aquí:
Empleadohereda dePersona- agrega una propiedad nueva:
position - usa
super(...)para inicializar la parte heredada - sobrescribe
saludar() - aprovecha
nameyobtenerEdad()desde la clase base
🚚 5. ¿Por qué el constructor recibe todas las propiedades?
Porque la clase hija debe pasarle a la clase padre los valores que esta necesita.
typescript
constructor(name: string, age: number, isDeveloper: boolean, puesto: string) {
super(name, age, isDeveloper);
this.position = puesto;
}Aquí pasa esto:
name,ageeisDevelopervan aPersonapuestose guarda enEmpleado
💡
super(...)llama al constructor de la clase padre. Sin eso, la parte heredada no se inicializa correctamente.
🔁 6. Sobrescribir métodos heredados
Sí, puedes redefinir un método que ya existe en la clase base.
La clase Persona tenía:
typescript
public saludar(): string {
return `Hola, mi nombre es ${this.name}, tengo ${this.age} años`;
}Pero en Empleado escribiste:
typescript
public saludar(): string {
return `Hola, trabajo como ${this.position}`;
}Eso significa que cuando llamas:
typescript
empleado.saludar();se ejecuta la versión de Empleado, no la de Persona.
🧪 ¿Puedo sobrescribir métodos heredados? Sí. Si la clase hija define un método con el mismo nombre, reemplaza al heredado al ejecutarse desde una instancia hija.
📦 7. ¿Por qué usar export?
Sin export, la clase no se puede importar desde otros archivos.
typescript
export class Empleado extends Persona {
// ...
}Y luego:
typescript
import { Empleado } from "./empleado.js";⚠️ Si olvidas
export, rompes la cadena de reutilización entre archivos.
🧩 8. Instanciar y probar la clase hija
En tu main.ts hiciste esto:
typescript
import { Empleado } from "./empleado.js";
let empleado = new Empleado("Juan", 30, true, "Desarrollador");
console.log(empleado.saludar());
console.log(empleado.ObtenerInfo());
console.log("Nombre:", empleado.name);Fíjate en la ventaja:
- llamas a métodos nuevos:
ObtenerInfo() - llamas a métodos sobrescritos:
saludar() - accedes a propiedades heredadas públicas:
name
Eso es justamente la herencia: el objeto hijo conserva lo útil de la base y añade lo suyo.
🧠 9. Compilación en cascada
Cuando compilas con:
bash
tsc main.tsTypeScript sigue la cadena de dependencias automáticamente:
- compila
main.ts - detecta que importa
empleado.ts - detecta que
empleado.tsimportaclase.ts - genera todos los
.jsnecesarios
Es un efecto dominó.
💡 No necesitas compilar manualmente uno por uno si la cadena de imports está bien hecha.
🖼️ Esquema visual
La siguiente imagen resume la idea de herencia y el efecto cascada al compilar:

🚨 ¿Qué debes tener en cuenta en producción?
Aunque en desarrollo te baste con compilar desde main.ts, en producción debes asegurarte de incluir todos los .js generados:
main.jsEmpleado.jsoempleado.jssegún tu flujo realclase.js
Si falta uno, las referencias se rompen y Node no encuentra los módulos.
⚠️ La compilación en cascada te ahorra trabajo local, pero el resultado final debe estar completo.
💻 PARTE PRÁCTICA
Archivos trabajados:
02-Ejercicios/Herencia/clase.ts02-Ejercicios/Herencia/empleado.ts02-Ejercicios/Herencia/main.ts
bash
cd 02-Ejercicios/Herencia
tsc main.ts && node main.jsSalida real verificada:
text
Hola, trabajo como Desarrollador
Hola, mi nombre es Juan, tengo 30 años y trabajo como Desarrollador
Nombre: JuanTodo verificado y corriendo. ✅
🏋️ EJERCICIOS CON SOLUCIÓN
💡 Desde aquí ya empezamos a practicar herencia con más seriedad. Algunos ejercicios usan un solo archivo y otros te obligan a separar la clase base, la clase hija y el archivo principal. Eso es intencional: así entrenas el flujo real de trabajo con varias páginas y varios módulos.
Ejercicio 1 — Animal y Perro
Crea una clase Animal con nombre y un método hacerSonido(). Luego crea una clase Perro extends Animal que sobrescriba hacerSonido().
Ver solución
typescript
class Animal {
public nombre: string;
constructor(nombre: string) {
this.nombre = nombre;
}
public hacerSonido(): string {
return "Sonido genérico";
}
}
class Perro extends Animal {
public hacerSonido(): string {
return "Guau guau";
}
}
const perro = new Perro("Max");
console.log(perro.nombre);
console.log(perro.hacerSonido());Terminal esperada:
$ tsc perro.ts
$ node perro.js
Max
Guau guauEjercicio 2 — Vehiculo y Auto
Crea una clase base Vehiculo con marca y un método describir(). Luego crea Auto que herede de Vehiculo y agregue puertas.
Ver solución
typescript
class Vehiculo {
public marca: string;
constructor(marca: string) {
this.marca = marca;
}
public describir(): string {
return `Marca: ${this.marca}`;
}
}
class Auto extends Vehiculo {
public puertas: number;
constructor(marca: string, puertas: number) {
super(marca);
this.puertas = puertas;
}
public obtenerInfo(): string {
return `${this.describir()}, Puertas: ${this.puertas}`;
}
}
const auto = new Auto("Toyota", 4);
console.log(auto.obtenerInfo());Terminal esperada:
$ tsc auto.ts
$ node auto.js
Marca: Toyota, Puertas: 4Ejercicio 3 — PersonaBase y Alumno
Crea una clase PersonaBase con nombre y edad. Luego crea Alumno que herede y agregue curso. Imprime un resumen con todos los datos.
Ver solución
typescript
class PersonaBase {
public nombre: string;
public edad: number;
constructor(nombre: string, edad: number) {
this.nombre = nombre;
this.edad = edad;
}
}
class Alumno extends PersonaBase {
public curso: string;
constructor(nombre: string, edad: number, curso: string) {
super(nombre, edad);
this.curso = curso;
}
public resumen(): string {
return `${this.nombre} tiene ${this.edad} años y estudia ${this.curso}`;
}
}
const alumno = new Alumno("Lucía", 21, "TypeScript");
console.log(alumno.resumen());Terminal esperada:
$ tsc alumno.ts
$ node alumno.js
Lucía tiene 21 años y estudia TypeScriptEjercicio 4 — Reutilizar método heredado
Crea una clase EmpleadoBase con un método presentarse(). Luego crea Gerente que herede de ella y agregue un método areaACargo().
Ver solución
typescript
class EmpleadoBase {
public nombre: string;
constructor(nombre: string) {
this.nombre = nombre;
}
public presentarse(): string {
return `Hola, soy ${this.nombre}`;
}
}
class Gerente extends EmpleadoBase {
public area: string;
constructor(nombre: string, area: string) {
super(nombre);
this.area = area;
}
public areaACargo(): string {
return `${this.presentarse()} y estoy a cargo de ${this.area}`;
}
}
const gerente = new Gerente("Carlos", "Tecnología");
console.log(gerente.areaACargo());Terminal esperada:
$ tsc gerente.ts
$ node gerente.js
Hola, soy Carlos y estoy a cargo de TecnologíaEjercicio 5 — Sobrescribir describir() en Rectangulo
Crea una clase Figura con un método describir(). Luego crea Rectangulo que herede de ella, agregue ancho y alto, y sobrescriba describir() mostrando además el área.
Ver solución
typescript
class Figura {
public nombre: string;
constructor(nombre: string) {
this.nombre = nombre;
}
public describir(): string {
return `Figura: ${this.nombre}`;
}
}
class Rectangulo extends Figura {
public ancho: number;
public alto: number;
constructor(ancho: number, alto: number) {
super("Rectángulo");
this.ancho = ancho;
this.alto = alto;
}
public calcularArea(): number {
return this.ancho * this.alto;
}
public describir(): string {
return `${super.describir()}, área: ${this.calcularArea()}`;
}
}
const rectangulo = new Rectangulo(8, 5);
console.log(rectangulo.describir());Terminal esperada:
$ tsc rectangulo.ts
$ node rectangulo.js
Figura: Rectángulo, área: 40Ejercicio 6 — Cuenta y CuentaPremium
Crea una clase Cuenta con titular y saldo. Luego crea CuentaPremium que herede y agregue un método retirar() con validación de saldo.
Ver solución
typescript
class Cuenta {
public titular: string;
public saldo: number;
constructor(titular: string, saldo: number) {
this.titular = titular;
this.saldo = saldo;
}
public mostrarSaldo(): string {
return `${this.titular} tiene ${this.saldo} soles`;
}
}
class CuentaPremium extends Cuenta {
public retirar(monto: number): string {
if (monto > this.saldo) {
return "Saldo insuficiente";
}
this.saldo -= monto;
return `Retiro exitoso. Nuevo saldo: ${this.saldo}`;
}
}
const cuenta = new CuentaPremium("Ana", 900);
console.log(cuenta.mostrarSaldo());
console.log(cuenta.retirar(250));Terminal esperada:
$ tsc cuenta-premium.ts
$ node cuenta-premium.js
Ana tiene 900 soles
Retiro exitoso. Nuevo saldo: 650Ejercicio 7 — Producto y ProductoConDescuento
Crea una clase Producto con nombre y precio. Luego crea ProductoConDescuento que herede y agregue porcentaje. Crea un método para devolver el precio final.
Ver solución
typescript
class Producto {
public nombre: string;
public precio: number;
constructor(nombre: string, precio: number) {
this.nombre = nombre;
this.precio = precio;
}
public mostrarInfo(): string {
return `${this.nombre}: S/ ${this.precio}`;
}
}
class ProductoConDescuento extends Producto {
public porcentaje: number;
constructor(nombre: string, precio: number, porcentaje: number) {
super(nombre, precio);
this.porcentaje = porcentaje;
}
public calcularPrecioFinal(): number {
return this.precio - (this.precio * this.porcentaje) / 100;
}
}
const producto = new ProductoConDescuento("Teclado", 150, 20);
console.log(producto.mostrarInfo());
console.log(`Precio final: S/ ${producto.calcularPrecioFinal()}`);Terminal esperada:
$ tsc producto-descuento.ts
$ node producto-descuento.js
Teclado: S/ 150
Precio final: S/ 120Ejercicio 8 — Separar Persona y Empleado en varios archivos
Ahora sí practica con varias páginas. Crea persona.ts, empleado.ts y main.ts. La clase Empleado debe extender a Persona y agregar puesto.
Ver solución
typescript
// persona.ts
export class Persona {
public nombre: string;
constructor(nombre: string) {
this.nombre = nombre;
}
public saludar(): string {
return `Hola, soy ${this.nombre}`;
}
}typescript
// empleado.ts
import { Persona } from "./persona.js";
export class Empleado extends Persona {
public puesto: string;
constructor(nombre: string, puesto: string) {
super(nombre);
this.puesto = puesto;
}
public describirTrabajo(): string {
return `${this.saludar()} y trabajo como ${this.puesto}`;
}
}typescript
// main.ts
import { Empleado } from "./empleado.js";
const empleado = new Empleado("Juan", "Backend Developer");
console.log(empleado.describirTrabajo());Terminal esperada:
$ tsc main.ts
$ node main.js
Hola, soy Juan y trabajo como Backend DeveloperEjercicio 9 — Usuario y Administrador en archivos separados
Crea una clase base Usuario y una clase hija Administrador. La hija debe agregar nivelAcceso y un método que muestre su rol.
Ver solución
typescript
// usuario.ts
export class Usuario {
public nombre: string;
constructor(nombre: string) {
this.nombre = nombre;
}
public presentacion(): string {
return `Usuario: ${this.nombre}`;
}
}typescript
// administrador.ts
import { Usuario } from "./usuario.js";
export class Administrador extends Usuario {
public nivelAcceso: string;
constructor(nombre: string, nivelAcceso: string) {
super(nombre);
this.nivelAcceso = nivelAcceso;
}
public mostrarRol(): string {
return `${this.presentacion()} | Acceso: ${this.nivelAcceso}`;
}
}typescript
// main.ts
import { Administrador } from "./administrador.js";
const admin = new Administrador("María", "Total");
console.log(admin.mostrarRol());Terminal esperada:
$ tsc main.ts
$ node main.js
Usuario: María | Acceso: TotalEjercicio 10 — Dispositivo y Laptop
Crea una clase Dispositivo con marca y modelo. Luego crea Laptop que herede y agregue ram. Debe mostrar un resumen técnico completo.
Ver solución
typescript
class Dispositivo {
public marca: string;
public modelo: string;
constructor(marca: string, modelo: string) {
this.marca = marca;
this.modelo = modelo;
}
public datosBase(): string {
return `${this.marca} ${this.modelo}`;
}
}
class Laptop extends Dispositivo {
public ram: number;
constructor(marca: string, modelo: string, ram: number) {
super(marca, modelo);
this.ram = ram;
}
public fichaTecnica(): string {
return `${this.datosBase()} con ${this.ram} GB de RAM`;
}
}
const laptop = new Laptop("Lenovo", "ThinkPad", 16);
console.log(laptop.fichaTecnica());Terminal esperada:
$ tsc laptop.ts
$ node laptop.js
Lenovo ThinkPad con 16 GB de RAMEjercicio 11 — Empleado y Vendedor con comisión
Crea una clase base Empleado con nombre y sueldoBase. Luego crea Vendedor que herede y agregue ventas. Debe calcular su pago total con comisión.
Ver solución
typescript
class Empleado {
public nombre: string;
public sueldoBase: number;
constructor(nombre: string, sueldoBase: number) {
this.nombre = nombre;
this.sueldoBase = sueldoBase;
}
}
class Vendedor extends Empleado {
public ventas: number;
constructor(nombre: string, sueldoBase: number, ventas: number) {
super(nombre, sueldoBase);
this.ventas = ventas;
}
public calcularPagoTotal(): number {
return this.sueldoBase + this.ventas * 0.1;
}
public resumen(): string {
return `${this.nombre} cobrará ${this.calcularPagoTotal()} soles`;
}
}
const vendedor = new Vendedor("Elena", 1400, 5000);
console.log(vendedor.resumen());Terminal esperada:
$ tsc vendedor.ts
$ node vendedor.js
Elena cobrará 1900 solesEjercicio 12 — CursoOnline extiende Curso
Crea una clase base Curso con titulo y duracion. Luego crea CursoOnline que herede y agregue plataforma. Usa super para reutilizar la descripción base.
Ver solución
typescript
class Curso {
public titulo: string;
public duracion: number;
constructor(titulo: string, duracion: number) {
this.titulo = titulo;
this.duracion = duracion;
}
public describir(): string {
return `${this.titulo} dura ${this.duracion} horas`;
}
}
class CursoOnline extends Curso {
public plataforma: string;
constructor(titulo: string, duracion: number, plataforma: string) {
super(titulo, duracion);
this.plataforma = plataforma;
}
public describir(): string {
return `${super.describir()} y se dicta en ${this.plataforma}`;
}
}
const curso = new CursoOnline("POO con TypeScript", 12, "Platzi");
console.log(curso.describir());Terminal esperada:
$ tsc curso-online.ts
$ node curso-online.js
POO con TypeScript dura 12 horas y se dicta en PlatziEjercicio 13 — Mini práctica real con tres archivos y dos métodos heredados
Practica un caso más cercano a proyecto real. Crea persona.ts, empleado.ts y main.ts. La clase Empleado debe heredar de Persona, agregar puesto, sobrescribir saludar() y tener además obtenerInfo().
Ver solución
typescript
// persona.ts
export class Persona {
public nombre: string;
public edad: number;
constructor(nombre: string, edad: number) {
this.nombre = nombre;
this.edad = edad;
}
public saludar(): string {
return `Hola, soy ${this.nombre}`;
}
}typescript
// empleado.ts
import { Persona } from "./persona.js";
export class Empleado extends Persona {
public puesto: string;
constructor(nombre: string, edad: number, puesto: string) {
super(nombre, edad);
this.puesto = puesto;
}
public saludar(): string {
return `Hola, trabajo como ${this.puesto}`;
}
public obtenerInfo(): string {
return `${this.nombre} tiene ${this.edad} años y trabaja como ${this.puesto}`;
}
}typescript
// main.ts
import { Empleado } from "./empleado.js";
const empleado = new Empleado("Juan", 30, "Frontend Developer");
console.log(empleado.saludar());
console.log(empleado.obtenerInfo());
console.log(`Nombre heredado: ${empleado.nombre}`);Terminal esperada:
$ tsc main.ts
$ node main.js
Hola, trabajo como Frontend Developer
Juan tiene 30 años y trabaja como Frontend Developer
Nombre heredado: Juan🧭 ¿Para qué sirve la herencia?
La herencia se usa para reutilizar código sin duplicarlo.
- Cuando varias clases comparten una base común
- Cuando quieres especializar una clase sin reescribir todo
- Cuando necesitas heredar propiedades y métodos ya probados
- Cuando una clase hija añade comportamiento nuevo encima de una clase padre
💡 En resumen:
extendste deja construir clases más específicas partiendo de una base ya hecha.
❓ Preguntas y respuestas (autoevaluación)
1. ¿Qué hace extends?
Hace que una clase herede propiedades y métodos de otra clase.
2. ¿Para qué sirve super(...)?
Para llamar al constructor de la clase padre e inicializar su parte heredada.
3. ¿Una clase hija puede agregar propiedades nuevas?
Sí. Hereda lo anterior y además puede definir sus propias propiedades y métodos.
4. ¿Puedo sobrescribir un método heredado?
Sí. Si defines el mismo método en la clase hija, su versión reemplaza a la de la base.
5. ¿Por qué tsc main.ts compila también otros archivos?
Porque TypeScript sigue automáticamente la cadena de imports y compila las dependencias.
📎 Apuntes relacionados
➡️ Siguiente
Polimorfismo y composición o seguir profundizando en POO.