Photo by Clément Hélardot on Unsplash
Typescript: O uso da palavra Super()
Qual é a importância da palavra reservada Super()?
Você já deve ter se deparado com a declaração no construtor de classes que recebem um super(). Por que precisamos? Como o usamos? E que tipo de erros recebemos quando não usamos? A palavra-chave super é usada para se referir aos métodos e propriedades definidos dentro da superclasse, mas calma, vamos entender tudo isso em partes iniciando pela herança!
A herança
É um princípio clássico e muito conhecido da Programação Orientada a Objetos que permite a criação de novas classes a partir de outras previamente criadas. Podemos chamar as novas classe de subclasses, ou classes derivadas; e as classes já existentes, que deram origem às subclasses, são chamadas de superclasses, ou classes base.
Então agora temos uma hierarquia de classes, mas o que isso nos ajuda ao desenvolver? Com a herança temos classes mais amplas e classes mais específicas. Uma subclasse herda métodos e atributos de sua superclasse; apesar disso, a subclasse pode escrevê-los novamente para uma forma mais específica de representar o comportamento do método herdado. E o que a herança tem haver com o super? Com ele podemos acessar atributos que são declarados no construtor e métodos que estão na superclasse e usá-los na subclasse. Vamos entender no próximo tópico.
A palavra reservada super() em JavaScript
Em outras linguagens como Java e Ruby a palavra reservada está presente. Em C# temos algo muito parecido com a palavra base:
// C#
using System;
public class Animal {
public string repColor = "brown";
}
public class Reptile: Animal {
string repColor = "green";
public void display() {
Console.WriteLine("Color: "+base.repColor); // base equivale a super
Console.WriteLine("Color: "+repColor);
}
}
// JAVA
public class Pessoa {
public String nome;
public String cpf;
public Date data_nascimento;
public Pessoa(String _nome, String _cpf, Date _data) {
this.nome = _nome;
this.cpf = _cpf;
this.data_nascimento = _data;
}
}
public class Aluno extends Pessoa {
public Aluno(String _nome, String _cpf, Date _data) {
super(_nome, _cpf, _data);
}
public String matricula;
}
// RUBY
class Pessoa
def initialize(nome)
@nome = validarNome(nome)
end
def validarNome(nome)
...
end
end
class PessoaFisica < Pessoa
def initialize(nome, cpf)
super(nome)
@cpf = validarCpf(cpf)
end
def validarCpf(cpf)
...
end
end
O JavaScript introduziu as classes no ECMAScript 6 e junto a palavra reservada super(). Isso abriu um leque de possibilidades para se trabalhar com essa linguagem! E já que o TypeScript é um superset do JavaScript, essas features fazem parte dele. Vamos ver um exemplo simples, mas que mostra muito bem o uso do super() dentro do Typescript :
A classe Animal representa uma superclasse. Outras classes irão se basear nela para se especializar e utilizar seus métodos e atributos. Note que temos na superclasse o atributo name sendo declarado no construtor. Agora vamos criar uma subclasse:
O que acontece se apenas tentarmos herdar a classe base sem a palavra reservada super()?
Temos três tipos de erro. Precisamos chamar o super() dentro do construtor antes de podermos acessar this e isso ocorre porque o objeto não é criado até super() ser chamado. Isso é uma regra! E segundo a documentação do Typescript você é obrigado a seguir dessa maneira:
" What’s more, before we ever access a property on this in a constructor body, we have to call super(). This is an important rule that TypeScript will enforce. - Typescript Documentation "
Para acessar métodos podemos utilizar o this também. Mas o recomendado sempre é usar a palavra super também. Veja o código corrigido:
Podemos também chamar o super() fora do construtor, dentro de métodos da subclasse e isso é muito útil. Como vemos na imagem acima, o método move da classe Lion consegue chamar super.move(distanceInMeters) da classe Animal.
Podemos executar o código utilizando a extensão Code Runner e com o ts-node instalado no projeto. Veja o resultado:
class Animal {
public name: string;
constructor(theName: string) {
this.name = theName;
}
public move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Lion extends Animal {
constructor(name: string) {
super(name)
}
move(distanceInMeters = 35) {
console.log("Run...");
super.move(distanceInMeters);
}
}
let simba: Animal = new Lion("Simba");
simba.move(33)
Resultado no console:
Mas pode estar se perguntando:
Por que isso não acontece automaticamente? Por que o compilador não pode simplesmente chamar super para mim?
Pode ser que aconteça que alguns casos, é necessário realizar algo antes da chamada do super(). Veja a subclasse Lion:
Veja que não tivemos nenhum erro. Mas é importante entender que existe casos específicos em que isso pode ocorrer.
Fico por aqui neste post e espero ter ajudado a entender melhor o objetivo dessa palavra reservada. Até o próximo! 🚀
Referencias:
ECMA: 262.ecma-international.org/6.0/#sec-super-k..
Documentação Typescript: typescriptlang.org/docs/handbook/classes.htm