Interface é uma estrutura que define o contrato em sua aplicação. Ela define a sintaxe para as classes a seguir. Classes que são derivadas de uma interface devem seguir a estrutura fornecida pela sua interface.
O compilador TypeScript não converte a interface para JavaScript. Ele usa a interface para verificação de tipo. Isto também é conhecido como “duck typing” ou “structural subtyping”.
Uma interface é definida com a palavra-chave interface
e pode incluir propriedades e declarações de métodos usando uma função ou uma função de seta.
Cópia
interface IEmployee { empCode: number; empName: string; getSalary: (number) => number; // arrow function getManagerName(number): string; }
No exemplo acima, a interface IEmployee
inclui duas propriedades empCode
e empName
. Ela também inclui uma declaração de método getSalaray
usando uma função de seta que inclui um parâmetro de número e um tipo de retorno de número. O método getManagerName
é declarado usando uma função normal. Isto significa que qualquer objeto do tipo IEmployee
deve definir as duas propriedades e dois métodos.
Interface como Tipo
Interface em TypeScript pode ser usada para definir um tipo e também para implementá-lo na classe.
A seguinte interface IEmployee
define um tipo de variável.
Cópia
interface KeyPair { key: number; value: string;}let kv1: KeyPair = { key:1, value:"Steve" }; // OKlet kv2: KeyPair = { key:1, val:"Steve" }; // Compiler Error: 'val' doesn't exist in type 'KeyPair'let kv3: KeyPair = { key:1, value:100 }; // Compiler Error:
No exemplo acima, uma interface KeyPair
inclui duas propriedades key
e value
. Uma variável kv1
é declarada como KeyPair
tipo. Portanto, ela deve seguir a mesma estrutura de KeyPair
. Isso significa que apenas um objeto com propriedades key
do tipo de número e value
do tipo de string pode ser atribuído a uma variável kv1
. O compilador TypeScript irá mostrar um erro se houver alguma alteração no nome das propriedades ou se o tipo de dados for diferente de KeyPair
. Outra variável kv2
também é declarada como KeyPair
tipo mas o valor atribuído é val
em vez de value
, portanto isto irá causar um erro. Da mesma forma, kv3 atribui um número à propriedade value
, assim o compilador irá mostrar um erro. Assim, TypeScript usa uma interface para assegurar a estrutura apropriada de um objeto.
Interface como Tipo de Função
Interface TypeScript também é usada para definir um tipo de função. Isto assegura a assinatura da função.
Cópia
interface KeyValueProcessor{ (key: number, value: string): void;};function addKeyValue(key:number, value:string):void { console.log('addKeyValue: key = ' + key + ', value = ' + value)}function updateKeyValue(key: number, value:string):void { console.log('updateKeyValue: key = '+ key + ', value = ' + value)} let kvp: KeyValueProcessor = addKeyValue;kvp(1, 'Bill'); //Output: addKeyValue: key = 1, value = Bill kvp = updateKeyValue;kvp(2, 'Steve'); //Output: updateKeyValue: key = 2, value = Steve
No exemplo acima, uma interface KeyValueProcessor
inclui uma assinatura de método. Isto define o tipo de função. Agora, podemos definir uma variável do tipo KeyValueProcessor
que só pode apontar para funções com a mesma assinatura definida na interface KeyValueProcessor
. Assim, addKeyValue
ou updateKeyValue
função é atribuída a kvp
. Assim, kvp
pode ser chamada como uma função.
Trying para atribuir uma função com uma assinatura diferente irá causar um erro.
function delete(key:number):void { console.log('Key deleted.')} let kvp: KeyValueProcessor = delete; //Compiler Error
Interface para o tipo de matriz
Uma interface também pode definir o tipo de matriz onde você pode definir o tipo de índice bem como valores.
Cópia
interface NumList { :number}let numArr: NumList = ;numArr;numArr;interface IStringList { :string}let strArr : IStringList;strArr = "TypeScript";strArr = "JavaScript";
No exemplo acima, a interface NumList
define um tipo de array com índice como número e valor como tipo de número. Da mesma forma, IStringList
define um array de string com índice como string e valor como string.
Propriedade Opcional
Por vezes, podemos declarar uma interface com propriedades em excesso, mas podemos não esperar que todos os objectos definam todas as propriedades da interface dada. Podemos ter propriedades opcionais, marcadas com um “?”. Nesses casos, os objetos da interface podem ou não definir essas propriedades.
Cópia
interface IEmployee { empCode: number; empName: string; empDept?:string;}let empObj1:IEmployee = { // OK empCode:1, empName:"Steve"}let empObj2:IEmployee = { // OK empCode:1, empName:"Bill", empDept:"IT"}
No exemplo acima, empDept
está marcado com ?
, portanto objetos de IEmployee
podem ou não incluir esta propriedade.
Ler apenas Propriedades
TypeScript fornece uma forma de marcar uma propriedade como somente leitura. Isto significa que uma vez atribuído um valor a uma propriedade, esta não pode ser alterada!
Cópia
interface Citizen { name: string; readonly SSN: number;}let personObj: Citizen = { SSN: 110555444, name: 'James Bond' }personObj.name = 'Steve Smith'; // OKpersonObj.SSN = '333666888'; // Compiler Error
No exemplo acima, a propriedade SSN
é só de leitura. Definimos o objeto personObj do tipo Citizen e atribuímos valores às duas propriedades de interface. Em seguida, tentamos alterar os valores atribuídos às duas propriedades-name
e SSN
. O compilador TypeScript mostrará um erro quando tentarmos alterar apenas a propriedade read only SSN
.
Interfaces de Extensão
Interfaces podem estender uma ou mais interfaces. Isto torna as interfaces de escrita flexíveis e reutilizáveis.
Cópia
interface IPerson { name: string; gender: string;}interface IEmployee extends IPerson { empCode: number;}let empObj:IEmployee = { empCode:1, name:"Bill", gender:"Male"}
No exemplo acima, a interface IEmployee
estende a interface IPerson
. Assim, objetos de IEmployee
devem incluir todas as propriedades e métodos da interface IPerson
caso contrário, o compilador mostrará um erro.
Implementando uma Interface
Similiar a linguagens como Java e C#, interfaces em TypeScript podem ser implementadas com uma Classe. A Classe implementando a interface precisa estar estritamente de acordo com a estrutura da interface.
Cópia
interface IEmployee { empCode: number; name: string; getSalary:(number)=>number;}class Employee implements IEmployee { empCode: number; name: string; constructor(code: number, name: string) { this.empCode = code; this.name = name; } getSalary(empCode:number):number { return 20000; }}let emp = new Employee(1, "Steve");
No exemplo acima, a interface IEmployee
é implementada na classe Employee usando a palavra-chave implementada. A classe implementadora deve definir estritamente as propriedades e a função com o mesmo nome e tipo de dados. Se a classe implementadora não seguir a estrutura, então o compilador irá mostrar um erro.
Obviamente, a classe implementadora pode definir propriedades e métodos extras, mas pelo menos deve definir todos os membros de uma interface.
No próximo capítulo, vamos aprender mais sobre as classes TypeScript.