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

Post anterior: TypeScript – Functions

No TypeScript, podemos trabalhar com “interfaces”. Uma interface funciona como um contrato entre si e qualquer classe ou estrutura que implemente sua interface. Isso significa que uma classe que implementa uma interface é obrigada a implementar todos os seus membros.
Primeiro vamos criar um exemplo sem o uso de uma interface. E entender a necessidade do uso de uma interface, para o exemplo.

window.onload = () => {
    function showAlert(args: { message: string }): void {
        alert(args.message);
    }

    showAlert({ message: "Mensagem de teste" });
};

Acima, criamos uma função chamada “showAlert”, que tem um argumento do tipo “object”, que por sua vez, exige um object com uma propriedade do tipo “string” (não deve chamar “message” necessariamente).
O método não deve ter retorno, já que está denotado como “void”. No corpo do método, apenas invocamos a função “alert”, passando como argumento, a propriedade “message” do objecto passado como argumento da função.
Abaixo, chamamos a função “showAlert” passando como argumento, um objecto genérico, com o atributo necessário.
Isso funciona normalmente, porem a manutenção desse exemplo, pode ser tornar difícil, dependendo da escala que o projeto tome. Neste exemplo não conseguimos garantir 100% que a estrutura do objeto deve ser. A interface pode resolver esse problema. Com ela, criamos um “contrato”, assim sabemos exatamente o que deve ser passado como parâmetro, e quem recebe o parâmetro também saberá. Além de centralizar o “contrato”, para todos os que utilizam.

interface IAlert {
    message: string;
    level?: number
}

window.onload = () => {
    function showAlert(args: IAlert): void {
        alert(args.message + (args.level > 0 ? ("\nNível: " + args.level): ""));
    }

    showAlert({ message: "Mensagem de teste", level: 2 });
};

Acima, criamos um interface com o nome “IAlert”, ela define que uma propriedade com o nome “message” do tipo string. E outra propriedade chamada “level” do tipo “number” é opcional. Repare que as propriedades da interface devem ser separadas por “;”.
Já na implementação da função “showAlert”, mudamos o tipo de argumento que deve ser passado para “IAlert”. E fizemos um ternário, para verificar se a propriedade “level” foi passada como parâmetro.

Interfaces com function types

As interfaces do TypeScript também permite trabalhar com funções. Assim, quem implementar a interface deverá implementar as funções definidas na interface.

interface ICalc {
    (number1: number, number2: number): number;
}

window.onload = () => {
    var sum: ICalc;
    sum = function (x: number, y: number): number {
        return x + y;
    };

    var resultSum = sum(10, 2);
    console.log("Resultado da soma", resultSum);
};

Acima, temos uma interface chamada “ICalc”. Ela define uma “function type”, que por sua vez, exige dois argumentos, ambos do tipo “number”, e que deve retornar “number” também.
Logo abaixo, declaramos uma variável chamada “sum”, que é do tipo “ICalc”. Na linha seguinte, definimos uma “function type” para variável “sum”. Onde somos “forçados” a ter dois argumentos, ambos do tipo “number” e retornar um “number” também. Repare que os nomes dos argumentos não coincidem. Isso não é necessário, desde de que os tipos sejam respeitados. Abaixo fazemos uso da “function type”, e “imprimimos” seu valor no console.

Class Types

O TypeScript permite que uma classe implemente uma interface. Vamos fazer um exemplo bem simples.

interface IClock {
    currentDate: Date;
    setDate(d: Date): void;
}

class Clock implements IClock {
    currentDate: Date;

    constructor() {
        this.currentDate = new Date();
    }

    setDate(d: Date) {
        this.currentDate = d;
    }
}

window.onload = () => {
    var myClock: Clock = new Clock();
    var date: Date = myClock.currentDate;

    console.log("Data", date);
};

No exemplo acima, temos uma interface chamada “IClock”, que define uma propriedade chamada “currentDate” do tipo “Date”; E um método chamado “setDate” que não deve retornar nada (já que está denotado como “void”); Neste mesmo método, deve ser passado como argumento, um objecto do tipo “Date”.
Abaixo temos uma classe chamada “Clock”, que por sua vez, implementa a interface “IClock”. Nesta classe, criamos uma propriedade “currentDate” do tipo Date, neste caso, o nome da propriedade deve ser respeitado, juntamente com seu tipo.
Também definimos um construtor, onde atribuímos uma instancia de “Date” para a propriedade “currentDate”. E por último, criamos um método chamado “setDate” (este também deve ter este nome, só assim será possível identificar se foi ou não implementado na classe base), que respeita a assinatura, definida na interface “IClock”.
Abaixo fazemos uso da classe “Clock”, atribuindo uma instancia de “Clock” para variável “myClock”. Em seguida, atribuímos o valor de “currentDate” para uma variável chamada “date”, do tipo “Date”. E por fim, “imprimimos” o valor da variável “date” no console.

Estendendo interfaces

O TypeScript permite que uma interface estenda a outra, assim é possível reaproveitar as definições de uma interface.

interface IPeople {
    name: string;
    age: number;
}

interface IEmployee extends IPeople {
    nameOffice: string
}

interface ITrainee extends IEmployee {
    amountOfWorkingHours: number
}

window.onload = () => {
    var trainee = <ITrainee> {};
    trainee.name = "John";
    trainee.age = 16;
    trainee.nameOffice = "Developer";
    trainee.amountOfWorkingHours = 6;
};

No exemplo acima, temos uma interface chamada “IPeople”, ela por sua vez, tem duas propriedades “name” do tipo “string”, e “age” do tipo “number”. Abaixo temos outra interface chamada “IEmployee”, que “herda” da interface “IPeople”. E tem apenas uma propriedade chamada “nameOffice” do tipo “string”, ou seja, um “IEmployee” é um “IPeople” (em outras palavras, um funcionário é uma pessoa, ao menos nesse contexto). E por último, temos a interface “ITrainee”, que deriva de “IEmployee”, porem tem que controlar a quantidade de horas que um estagiário pode trabalhar, através da propriedade “amountOfWorkingHours” do tipo “number”.
Já em “onload” temos uma variável tipada com “ITrainee” como o nome “trainee”. Repare que todas as propriedades das interfaces de nível mais alto, estão disponíveis para a interface “ITrainee” também, que é do nível mais baixo, que definimos.

Continue lendo em TypeScript – Classes.

Espero ter ajudado!
Até a próxima!