Menu

Classe abstrata em TypeScript: métodos, propriedades e interface

Uma classe abstrata em TypeScript é uma classe base que não pode ser instanciada e pode deixar métodos para as subclasses implementarem. Veja métodos e propriedades abstratos, o padrão template method, tipos de construtor abstratos e quando uma interface é a escolha melhor.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Uma classe abstrata é uma classe base marcada como abstract. Ela não pode ser criada com new e pode declarar métodos abstract sem corpo, que toda subclasse precisa implementar.

Shape compartilha describe() com todas as subclasses e obriga cada uma a fornecer area(). O tipo Shape[] guarda qualquer mistura de subclasses.

Uma classe abstrata não pode ser instanciada

Chamar new em uma classe abstrata é erro de compilação, porque o objeto teria métodos sem implementação:

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

Essa é uma regra de tempo de compilação. O abstract é apagado da saída, então o Shape gerado é uma classe JavaScript comum, e código JavaScript sem tipos ainda poderia chamar new Shape(). Quando uma biblioteca precisa de uma proteção em tempo de execução, o construtor pode verificar new.target:

Métodos e propriedades abstratos

Uma subclasse precisa implementar todos os membros abstratos, ou ser ela mesma abstrata. Faltar um gera o erro TS2515, que diz algo como Non-abstract class 'Square' does not implement inherited abstract member area from class 'Shape', ou o TS2654, que lista todos quando faltam vários.

Campos, getters e métodos podem ser abstratos, e podem ser protected:

Um método abstrato não tem corpo; escrever um gera o erro TS1245 (Method 'x' cannot have an implementation because it is marked abstract). Uma classe abstrata não precisa ter nenhum membro abstrato: o abstract sozinho só impede a instanciação direta.

O padrão template method

O motivo mais comum para escrever uma classe abstrata: a classe base fixa a ordem dos passos, e cada subclasse preenche os passos que variam.

Classes abstratas podem ser genéricas, como aqui, para que cada subclasse escolha o tipo do registro.

Tipos de construtor abstratos

typeof Shape de uma classe abstrata é um construtor que você não pode chamar, então um parâmetro tipado como typeof Shape não pode fazer new c(). Quando uma função deve aceitar classes abstratas (por exemplo para registrá-las ou verificar instanceof), tipe-a com uma construct signature abstrata:

abstract new aceita classes abstratas e concretas; new simples só aceita as concretas.

Classe abstrata vs interface

Classe abstrataInterface
Contém códigosim: métodos, inicializadores de campos, construtornão, só tipos
Existe em tempo de execuçãosimnão, é apagada
instanceoffuncionaimpossível
Uma classe pode usaruma (extends)várias (implements)
Modificadores de acessoprivate, protected, publicsó membros públicos
Tipo para objetos simplessó se não tiver membros private/protected, e aí o instanceof falhasim, qualquer valor com o formato

A regra prática: uma interface quando você só precisa descrever um formato (o caso mais comum, e funciona também para objetos literais), uma classe abstrata quando as subclasses compartilham implementação de verdade e você quer que o compilador as obrigue a preencher as lacunas. As duas se combinam bem: uma interface para o contrato público, e uma classe abstrata como uma base conveniente que o implementa. Veja interface vs type para a outra comparação comum.

Erros comuns

  • Usar uma classe abstrata onde uma interface bastaria. Se a classe base não tem código, ela é uma interface com peso extra em tempo de execução e o limite de herança única.
  • Tentar static abstract. Não é permitido. Membros estáticos não podem ser abstratos.
  • Esperar um erro em tempo de execução ao usar new em uma classe abstrata. Não há nenhum, a menos que você escreva a verificação com new.target.
  • Chamar um método abstrato a partir do construtor da base. Ele roda antes de os campos da subclasse serem inicializados, então a implementação os vê como undefined.

Perguntas frequentes

O que é uma classe abstrata no TypeScript?

Uma classe marcada como abstract que não pode ser criada com new e pode declarar membros abstract sem implementação. As subclasses precisam implementar todos os membros abstratos. É um jeito de compartilhar código e exigir um formato ao mesmo tempo.

Qual é a diferença entre uma classe abstrata e uma interface no TypeScript?

Uma classe abstrata pode conter código de verdade (métodos implementados, campos com valores iniciais, um construtor) e existe em tempo de execução, então o instanceof funciona com ela; uma classe só pode estender uma. Uma interface não tem código, é apagada na compilação, e uma classe pode implementar várias. Use uma classe abstrata para compartilhar comportamento, uma interface para descrever um formato.

Uma classe abstrata pode ter um construtor no TypeScript?

Sim. Ele roda quando uma subclasse chama super(...). Você continua não podendo chamar new na própria classe abstrata (TS2511: Cannot create an instance of an abstract class).

Métodos estáticos podem ser abstratos no TypeScript?

Não. O abstract só se aplica a membros de instância; static abstract gera o erro TS1243 ('static' modifier cannot be used with 'abstract' modifier). Para exigir um formato estático, tipe o construtor com uma interface que inclua o membro estático e verifique a classe contra ela.

Uma classe abstrata é aplicada em tempo de execução?

Não. O abstract é apagado, então a classe compilada é JavaScript comum e código JavaScript puro ainda poderia chamar new nela. Se isso importar, verifique new.target no construtor e lance um erro.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR