Este post é o quarto de uma série de 6 posts sobre TypeScript. Veja os detalhes dos posts aqui.

Post anterior: TypeScript – Interfaces

O TypeScript da condição de trabalhar com classes. Uma classe é uma representação de um tipo de objeto. Uma estrutura que descreve o objeto. Assim com uma planta pode ser usada para criar diversas construções, uma única classe pode ser usada para criar quantos objetos forem necessários. Uma classe é composta de atributos (características) e métodos (ações). Vamos criar um exemplo básico, para entender a estrutura básica de uma classe no TypeScript.

class People {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    walk(): void {
        console.log(this.name + " (" + this.age + ") is walking");
    }
}

window.onload = () => {
    var peopleJonh: People = new People("Jonh", 20);
    peopleJonh.walk();
};

No exemplo acima, temos uma classe chamada “People”, que possui dois atributos, “name” do tipo “string”, e “age” do tipo “number”.
Temos um construtor, que pode sua vez, tem dois argumentos, com os nomes e tipos dos atributos. O que diferencia entre as variáveis locais (no contexto do construtor) e os atributos da classe, é a palavra reservada “this”. Ao usar “this.name” por exemplo, estamos informando que a variável local “name” deve passado uma referencia para o atributo de classe “name”. O mesmo vale para variável e atributo “age”.
Também temos um método chamado “walk”, que não tem retorno algum (repare que está denotado como “void”). Já sua implementação, temos um simples “console.log”, para “imprimir” o nome da pessoa, juntamente com a idade no console do navegador.
E por fim, fazemos uso da classe “People”, atribuindo a uma instancia da classe, para variável “peopleJonh”, que corresponde ao mesmo tipo. E invocamos o método “walk”.

Herança entre classes

A Herança possibilita que as classes compartilhem seus atributos e métodos. A herança ajuda a reaproveitar implementações.
Gostaria de recomendar a leitura desse post Programe voltado para a interface e não para a implementação.

Vamos criar um exemplo prático.

class Product {
    name: string;
    price: number

    constructor(name: string, price: number) {
        this.name = name;
        this.price = price;
    }

    getPriceWithDiscount(): number {
        var date: Date = new Date();
        var discount: number = 0.10;
        if (date.getDay() == 1 || date.getDay() == 6)
            discount = 0.12;

        return this.price - (this.price * discount);
    }
}

enum Color { blue, white, red, black };

class Car extends Product {
    color: Color;

    constructor(name: string, price: number, color: Color) {
        super(name, price);
        this.color = color;
    }

    getPriceWithDiscount(): number {
        return this.price - (this.price * 0.2);
    }
}

window.onload = () => {
    var product: Product = new Product("Table", 100.10);
    console.log("Preço da mesa", product.getPriceWithDiscount());

    var car: Car = new Car("Table", 1000.99, Color.black);
    console.log("Preço do carro", car.getPriceWithDiscount());
};

No exemplo acima, temos algumas coisas novas. Primeiro vamos ver a classe “Product”. Ela possui dois atributos. “name” do tipo “string”. E “price” do tipo “number”. Tem declarado um construtor, que exige dois argumentos, com os mesmos nome e tipos de atributos da classe.
E possui um método chamado “getPriceWithDiscount”, que deve retornar um “number”. Neste método possui uma implementação simples. O desconto padrão é de 0.10, porem se for sábado ou domingo, o desconto deve ser de 0.12. E por fim, o método que calcula e retorna o preço com desconto.

Logo abaixo, declaramos um enum, chamado “Color”, ele sera utilizado como parâmetro.

Abaixo temos uma classe chamada “Car”, ela por sua vez, é herdeira de “Product”, perceba que utilizamos a palavra chave “extends” seguida da classe “Product”. Esta mesma classe possui um atributo que só faz sentido pra ela “color”, que é do tipo “Color” (nosso enum).
Esta classe também possui um construtor, parecido com o construtor da classe “Product”, com a diferença que tem um parâmetro a mais, chamado “color” do tipo “Color”. Outra novidade é o uso de “super”, este serve para utilizar o construtor da classe base (no caso, a classe “Product”), assim os atributos “name” e “price” ainda serão utilizados. E por fim, no construtor, estamos definindo o valor do atributo “color”.
Ainda na classe “Car”, estamos sobrecarregando o método “getPriceWithDiscount”, ou seja, uma instancia da classe “Car”, não terá a mesma regra definida na classe “Product”. O desconto sera de 0.2, em qualquer dia.

Logo abaixo, fazemos uso das classes “Product” e “Car”. Repare que a assinatura do construtor da classe “Product” é diferente do construtor da classe “Car”. E o calculo de desconto tem diferença, no resultado final.

Visibilidade – public/private

Por padrão as propriedades de uma classe no TypeScript tem o modificador de acesso “public”. Um membro “public” pode ser acessado de qualquer local. Já um membro “private”, é acessível apenas para a própria classe.

class Product {
    private price: number;

    constructor(price: number) {
        this.price = price;
    }

    public priceWithDiscount() {
        return this.price - (this.price * 0.10);
    }
}


window.onload = () => {
    var product: Product = new Product(100.10);
    console.log("Preço do produto com desconto", product.priceWithDiscount());
};

No exemplo acima, temos uma classe chamada “Product”, que possui apenas uma propriedade “price” do tipo “number”, repare que ela é “private”, ou seja, não pode ser acessada de fora, somente é visível na própria classe. Também temos um construtor que pede um argumento, para definir o valor de “price”. E por fim temos um método “public” chamado “priceWithDiscount”, ele apenas retorna o preço com desconto de 0.10. Se tentarmos acessar a propriedade “price”, uma exceção será lançada. E por fim, fazemos uso da classe “Product” e “imprimimos” o valor do produto com desconto, utilizando o método “priceWithDiscount”.

Static

Um membro estático em uma classe (propriedade ou método) só pode ser acessado em nível de classe, e não em nível de instancia. Vamos modificar o exemplo anterior.

class Product {
    private price: number;
    public static discount: number = 0.10;

    constructor(price: number) {
        this.price = price;
    }

    public priceWithDiscount() {
        return this.price - (this.price * Product.discount);
    }
}


window.onload = () => {
    var product: Product = new Product(100.10);
    console.log("Preço do produto com desconto (" + Product.discount + ")", product.priceWithDiscount());
};

No exemplo acima, adicionamos uma propriedade estática, com visibilidade “public”, chamada “discount”, do tipo “number”, que possui o valor 0.10. E acessamos esta propriedade para calcular o desconto, no método “priceWithDiscount” (acessando Product.discount).

Get/Set

O TypeScript permite definir “get” (obter) e “set” (atribuir). Com esses recursos, podemos manipular o valor de uma propriedade, e encapsular / centralizar as regras para obter um valor e definir um valor. Vamos fazer um exemplo bem simples.

class Product {
    private _name: string;

    public get name(): string {
        return this._name;
    }

    public set name(name: string) {
        this._name = name;
    }
}

window.onload = () => {
    var product: Product = new Product();
    product.name = "Table";
    console.log("Nome do produto", product.name);
};

No exemplo acima, temos uma propriedade privada, chamada “_name”, do tipo “string”. E temos dois métodos, um para “get” outro para “set”. O “get” apenas retorna o valor da propriedade “_name”. E o o “set” apenas definir o valor que foi passado como argumento. Repare que ambos tem o mesmo nome. Em ambos, poderíamos ter definimo alguma regra, assim quem utilizasse o get/set estaria sujeito da respeitar.

Continue lendo em TypeScript – Módulos.

Espero ter ajudado!
Até a próxima!

Publicidade