DEV Community

Wiley Marques
Wiley Marques

Posted on

TypeScript vs Dart - Interfaces

Nesse artigo falaremos brevemente sobre a utilização de interfaces em TypeScript e como Dart provê a mesma funcionalidade.

TypeScript

Assim como eu muitas linguagens, TypeScript possui suporte a interfaces. Uma funcionalidade muito utilizada para criarmos contratos onde há a comunicação entre dois ou mais componentes de software.

Para exemplificar, vamos criar uma função em TypeScript. Essa função irá receber um nome e um sobrenome. E retornará o nome inteiro:

function joinNames(firstName: string, lastName: string): string {
  return `${firstName} ${lastName}`;
}
const fullName = joinNames('Wiley', 'Marques');
console.log(fullName); // 'Wiley Marques'
Enter fullscreen mode Exit fullscreen mode

Abrir no TypeScript Playground

Agora, para exemplificar o uso de uma interface, vamos alterar o recebimento de parâmetros na função. Ao invés de receber firstName e lastName, vamos passar a receber um objeto contendo essas duas propriedades.

Para isso, criaremos a interface Person com essas propriedades. Alteraremos a função para receber um objeto com o tipo sendo a interface. E alteraremos a forma de executar a função passando um objeto condizente com a interface:

interface Person {
  firstName: string;
  lastName: string;
}

function joinNames(person: Person): string {
  return `${person.firstName} ${person.lastName}`;
}

const fullName = joinNames({
  firstName: 'Wiley',
  lastName: 'Marques',
});

console.log(fullName); // 'Wiley Marques'
Enter fullscreen mode Exit fullscreen mode

Abrir no TypeScript Playground

Criamos a interface e fizemos a função joinNames recebê-la como parâmetro. Mas interfaces não são usadas apenas para definir as assinaturas de funções. Também são usadas para definir um contrato a ser seguido por classes em um software. Então vamos modificar o exemplo acima para demonstrar essa utilização.

Criaremos uma classe de nome Wiley para realizar a criação de um objeto. Como o objeto será usado como parâmetro para a função joinNames, ele deverá respeitar o contrato (ou interface) Person. Portanto teremos de implementar a interface Person na classe Wiley e definir propriedades correspondentes às esperadas pela interface. Tendo o seguinte código:

interface Person {
  firstName: string;
  lastName: string;
}

class Wiley implements Person { // Implementando a interface `Person`

  // Definindo as propriedades requeridas na interface
  public firstName: string = 'Wiley';
  public lastName: string = 'Marques';

  // Podemos adicionar qualquer outra propriedade
  public hasChildren: boolean = true;
}

function joinNames(person: Person): string {
  return `${person.firstName} ${person.lastName}`;
}

const wiley = new Wiley(); // Criando um objeto `Wiley`
const fullName = joinNames(wiley); // Passando `wiley` para a função

console.log(fullName);
Enter fullscreen mode Exit fullscreen mode

Abrir no TypeScript Playground

Como podemos ver, apesar de o objeto wiley ser do tipo Wiley, podemos utilizá-lo como parâmetro para a função joinNames. Isso se deve ao fato de a classe Wiley implementar a interface Person e a função joinNames estar preparada para receber qualquer objeto que implemente Person.

Dart

Agora vejamos como Dart funciona nesse quesito.

Dart possui uma extensa documentação sobre todas as funcionalidades disponíveis na linguagem. Essa documentação pode ser vista em: A tour of the Dart language. Lá podemos ver que em Dart não existe uma forma explícita para criação interfaces. A alternativa ofertada pela linguagem é a utilização de Classes Abstratas.

Em Dart, existe um conceito chamado de Interface Implícita. Basicamente, qualquer classe também é implicitamente uma interface! Portanto, qualquer classe (abstrata ou não) pode ser implementada por outra quando necessário.

Indo ao código e seguindo a recomendação da documentação, a classe abstrata Person ficaria assim:

abstract class Person {
  String get firstName;
  String get lastName;
}
Enter fullscreen mode Exit fullscreen mode

Um ponto a se notar aqui é que, além de usarmos uma classe abstrata, foi necessário um getter ao invés de uma simples propriedade.

Agora, continuando o exercício, vamos converter o último exemplo da sessão anterior para Dart. Ficando com o seguinte código:

abstract class Person {
  String get firstName;
  String get lastName;
}

class Wiley implements Person { // Classe `Wiley` implementando classe `Person`
  String firstName = 'Wiley';
  String lastName = 'Marques';
  bool hasChildren = true;
}

String joinNames(Person person) {
  return '${person.firstName} ${person.lastName}';
}

void main() {
  final wiley = new Wiley();
  final fullName = joinNames(wiley);
  print(fullName);
}
Enter fullscreen mode Exit fullscreen mode

Abrir no Dart Pad

Assim temos uma Classe Abstrata sendo utilizada como uma definição de contrato.

Bônus

Vamos acrescentar uma curiosidade interessante. Em TypeScript, as classes também possuem interfaces implícitas! Com isso, também é possível definir uma classe abstrata e a utilizarmos como um contrato, semelhante a como fizemos em Dart.

Em código, a classe abstrata ficaria assim:

abstract class Person {
  abstract get firstName(): string;
  abstract get lastName(): string;
}
Enter fullscreen mode Exit fullscreen mode

E o exemplo inteiro seria:

abstract class Person {
  abstract get firstName(): string;
  abstract get lastName(): string;
}

class Wiley implements Person {
  public firstName: string = 'Wiley';
  public lastName: string = 'Marques';
  public hasChildren: boolean = true;
}

function joinNames(person: Person): string {
  return `${person.firstName} ${person.lastName}`;
}

const wiley = new Wiley();
const fullName = joinNames(wiley);

console.log(fullName);
Enter fullscreen mode Exit fullscreen mode

Abrir no TypeScript Playground

Ou seja, TypeScript dá suporte às duas formas!

Conclusão

Vimos como implementar interfaces em TypeScript e qual a alternativa proposta por Dart. Além de vermos como TypeScript oferece o mesmo suporte a interfaces implícitas presentes em Dart.

Nos próximos artigos, veremos outras comparações. Obrigado. E até logo!

Oldest comments (0)