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!
Artigo muito esclarecedor. Valeu mesmo!