Menu

Clases abstractas en TypeScript: métodos, propiedades e interfaces

Una clase abstracta en TypeScript es una clase base que no se puede instanciar y que puede dejar métodos para que los implementen las subclases. Aprende los métodos y propiedades abstractos, el patrón template method, los tipos de constructor abstractos y cuándo es mejor una interfaz.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Una clase abstracta es una clase base marcada como abstract. No se puede crear con new, y puede declarar métodos abstract sin cuerpo, que cada subclase debe implementar.

Shape comparte describe() con todas las subclases y obliga a cada una a aportar area(). El tipo Shape[] admite cualquier mezcla de subclases.

Una clase abstracta no se puede instanciar

Llamar a new sobre una clase abstracta es un error de compilación, porque el objeto tendría métodos sin implementación:

index.ts(6,11): error TS2511: Cannot create an instance of an abstract class.

Es una regla en tiempo de compilación. abstract se borra de la salida, así que el Shape generado es una clase normal de JavaScript, y código JavaScript sin tipos podría seguir llamando a new Shape(). Cuando una librería necesita una protección en tiempo de ejecución, el constructor puede comprobar new.target:

Métodos y propiedades abstractos

Una subclase debe implementar todos los miembros abstractos, o ser abstracta a su vez. Si falta uno, es el error TS2515, que dice algo como Non-abstract class 'Square' does not implement inherited abstract member area from class 'Shape', o TS2654, que los enumera todos cuando faltan varios.

Los campos, los getters y los métodos pueden ser abstractos, y pueden ser protected:

Un método abstracto no tiene cuerpo; escribirle uno es el error TS1245 (Method 'x' cannot have an implementation because it is marked abstract). Una clase abstracta no tiene por qué tener ningún miembro abstracto: abstract por sí solo impide la instanciación directa.

El patrón template method

La razón más habitual para escribir una clase abstracta: la clase base fija el orden de los pasos, y cada subclase rellena los pasos que varían.

Las clases abstractas pueden ser genéricas, como aquí, para que cada subclase elija el tipo de registro.

Tipos de constructor abstractos

typeof Shape para una clase abstracta es un constructor que no se puede llamar, así que un parámetro de tipo typeof Shape no puede hacer new c(). Cuando una función debe aceptar clases abstractas (por ejemplo para registrarlas o comprobar instanceof), típala con una firma de construcción abstracta:

abstract new acepta clases abstractas y concretas; new a secas solo acepta las concretas.

Clase abstracta frente a interfaz

Clase abstractaInterfaz
Contiene códigosí: métodos, inicializadores de campos, constructorno, solo tipos
Existe en tiempo de ejecuciónsíno, se borra
instanceoffuncionaimposible
Una clase puede usaruna (extends)muchas (implements)
Modificadores de accesoprivate, protected, publicsolo miembros públicos
Tipo para objetos normalessolo si no tiene miembros private/protected, y entonces instanceof fallasí, cualquier valor con esa forma

La regla práctica: una interfaz cuando solo necesitas describir una forma (el caso más habitual, y también funciona con objetos literales), una clase abstracta cuando las subclases comparten implementación real y quieres que el compilador las obligue a rellenar los huecos. Las dos se combinan bien: una interfaz para el contrato público y una clase abstracta como base práctica que la implementa. Consulta interface frente a type para la otra comparación habitual.

Errores habituales

  • Usar una clase abstracta donde bastaría una interfaz. Si la clase base no tiene código, es una interfaz con peso extra en tiempo de ejecución y el límite de herencia única.
  • Intentar static abstract. No está permitido. Los miembros estáticos no pueden ser abstractos.
  • Esperar un error en tiempo de ejecución al hacer new sobre una clase abstracta. No lo hay, salvo que escribas la comprobación de new.target.
  • Llamar a un método abstracto desde el constructor base. Se ejecuta antes de que se inicialicen los campos de la subclase, así que la implementación los ve como undefined.

Preguntas frecuentes

¿Qué es una clase abstracta en TypeScript?

Una clase marcada como abstract que no se puede crear con new y que puede declarar miembros abstract sin implementación. Las subclases deben implementar todos los miembros abstractos. Es una forma de compartir código y exigir una forma al mismo tiempo.

¿Qué diferencia hay entre una clase abstracta y una interfaz en TypeScript?

Una clase abstracta puede contener código real (métodos implementados, campos con valores iniciales, un constructor) y existe en tiempo de ejecución, así que instanceof funciona con ella; una clase solo puede extender una. Una interfaz no tiene código, se borra al compilar, y una clase puede implementar muchas. Usa una clase abstracta para compartir comportamiento y una interfaz para describir una forma.

¿Puede una clase abstracta tener constructor en TypeScript?

Sí. Se ejecuta cuando una subclase llama a super(...). Lo que sigue sin poder hacerse es llamar a new sobre la propia clase abstracta (TS2511: Cannot create an instance of an abstract class).

¿Pueden ser abstractos los métodos estáticos en TypeScript?

No. abstract solo se aplica a miembros de instancia; static abstract es el error TS1243 ('static' modifier cannot be used with 'abstract' modifier). Para exigir una forma estática, tipa el constructor con una interfaz que incluya el miembro estático y comprueba la clase contra ella.

¿Se aplica una clase abstracta en tiempo de ejecución?

No. abstract se borra, así que la clase compilada es JavaScript normal y el código JavaScript normal podría seguir llamando a new sobre ella. Si eso importa, comprueba new.target en el constructor y lanza un error.

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR