Executando verificação de segurança...
3

Fala @guilzms, tudo tranquilo?

Minha visão sobre Type e Interface

A respeito de qual "modelagem" utilizar em relação ao projeto, no curso que estou fazendo de typescript tive a seguinte visão sobre o uso do alias type e interface:

TYPE: Geralmente utilizado para criar um atalho (alias) para um tipo customizado. Utilizado em tipos primitivos (string, boolean, number...):

type Categorias = 'design' | 'codigo' | 'descod';

function pintarCategoria(categoria: Categorias) {
  if (categoria === 'design') {
    console.log('Pintar vermelho');
  } else if (categoria === 'codigo') {
    console.log('Pintar verde');
  } else if (categoria === 'descod') {
    console.log('Pintar roxo');
  }
}

INTERFACE: Geralmente são utilizadas para definirmos objetos, entretanto não possibilita renomear tipos primitivos.

interface InterfaceProduto {
    nome: string;
    preco: number;
    teclado: number;
}

function preencherDados(dados: InterfaceProduto) {
  document.body.innerHTML += `
  <div>
    <h2>${dados.nome}</h2>
    <p>R$ ${dados.preco}</p>
    <p>Inclui teclado: ${dados.teclado ? 'sim' : 'não'}</p>
  </div>
  `;
}

Um bom ponto de observação, é que quando você cria um alias type,você está criando um apelido e nada mais. O Type é do tipo fechado, onde não é possível criar diferentes "versões" do mesmo tipo, então sua repetição gerará um Erro de TS:

// TYPE
type Window = {
  title: string
}

type Window = {
  ts: TypeScriptAPI
}

 // Error: Duplicate identifier 'Window'.

Para realizar a adição de uma nova propriedade a um Type, seria necessário fazer o seguinte processo:

type TipoCarro = {
  rodas: number;
  portas: number;
};

type TipoCarroComPreco = TipoCarro & {
  preco: number;
};

const dado1: TipoCarroComPreco = {
  preco: 20000,
  rodas: 4,
  portas: 5,
};

Já a Interface é do tipo aberta, então a mesma possibilita adicionar ou alterar campos, e também extende-la apenas redeclarando a mesma :

// Redeclaração de campos
interface InterfaceCarro {
  rodas: number;
  portas: number;
}

interface InterfaceCarro {
  preco: number;
}

const dado2: InterfaceCarro = {
  preco: 20000,
  rodas: 4,
  portas: 5,
};

Conclusão

O Matheus Benites - PapoDe.Dev dá um excelente panorama sobre a utilização de types e Interface:

se precisamos declarar os tipos de uma classe e seus metodos utilizamos interface;
se precisamos declarar os tipo das props de uma função usamos alias type;
se precisar criar uma definição de tipo que será extendida por algo, nós usamos interface;
se estamos criando um generic type para alguma funcionalidade, usamos interface.

Espero ter ajudado, até mais!

Fontes:

Matheus Benites - PapoDe.Dev
Documentação - Curso de Typescript - Origamid

Carregando publicação patrocinada...
1

Muito boa essa definição! Gostei!

Após a leitura do material e das suas conclusões vejo que está parecido com a metodologia que estou aplicando atualmente onde:

  • Parametros de métodos e funções: Type
  • Classe, métodos e callbacks: Interface
  • métodos e callbacks privados não repetidos em outras classes: Type

E quando digo sobre métodos repetidos me refiro a isto por exemplo:

interface modeloInterface {
    dado: string;
}

class FornecedorUm {
    consumirApi(): modeloInterface {
        return {
            dado: 'oi'
        }
    }
}

class FornecedorDois {
    consumirApi(): modeloInterface {
        return {
            dado: 'tchau'
        }
    }
}

Nestes exemplos o retorno dado no método consumirApi precisa ser identico em todas as classes.

E o legal que vi em vários materiais, seu comentário e também o que estava pensando sobre os type é que eles são somente um alias enquanto que a interface, assim como em outras linguagens, é um contrato que deve ter seus parâmetros e métodos aplicados dentro da classe ou método onde ela é aplicada obrigatóriamente enquanto que o type não.

Além do exemplo que citei no post original eu poderia implementar esse nível de interfaces também diretamente na classe.

interface EmpresaCallback {
    doc: string
    razao: string
}

type BrasilAPITypes = {
  cnpj: string;
  razao_social: string;
};

interface GlobalInterface {
    formataPesquisaCnpj: (param: BrasilAPITypes) => EmpresaCallback
}

class ConsultaBrasilAPI implements GlobalInterface  {
    formataPesquisaCnpj(callbackApi: BrasilAPITypes): EmpresaCallback {
        return {
            doc: callbackApi.cnpj,
            razao: callbackApi.razao_social
         }
    }
}

Mas essa modelagem no meu caso eu preferi não seguir porque a classe em si é modelo "único" e não vai se repetir enquanto que o meu método formataPesquisaCnpj poderá se repetir em outra classe que receberá dados de outra fonte e o callback delas devem ser identicos indiferente da fonte de dados. Além que quero evitar o "interfaces hell" em toda a aplicação assim como existia com o callback hell antes do async/await hahaha :-D

Pelo que estou vendo de acordo com os comentários, alguns materiais, troca de experiências e o pouco que tenho de conhecimento é que não existe muito bem denifino do Typescript um "manual de boas práticas" sobre uso de interfaces diferentemente de outras linguagens.