<h2>O que é uma Interface em TypeScript?</h2>
<p>Uma interface em TypeScript é um contrato que define a estrutura de um objeto. Ela descreve quais propriedades e métodos um objeto deve ter, sem implementação — apenas a assinatura. Pense em uma interface como um molde ou blueprint: você a define, e qualquer classe ou objeto que "implemente" essa interface deve seguir as regras estabelecidas.</p>
<p>A grande vantagem é o <strong>type checking em tempo de desenvolvimento</strong>. O TypeScript verifica se você está usando o objeto corretamente antes mesmo de executar o código. Isso reduz bugs e torna seu código mais seguro e previsível. Diferente de classes, interfaces não existem em tempo de execução — o compilador as remove durante a transpilação para JavaScript.</p>
<pre><code class="language-typescript">// Definindo uma interface simples
interface Usuario {
id: number;
nome: string;
email: string;
ativo: boolean;
}
// Criando um objeto que segue a interface
const usuario: Usuario = {
id: 1,
nome: "João Silva",
email: "joao@example.com",
ativo: true
};
// Se tentar atribuir um objeto incompleto, TypeScript gera erro
const usuarioIncompleto: Usuario = {
id: 2,
nome: "Maria"
// ❌ Erro: propriedades 'email' e 'ativo' não foram atribuídas
};</code></pre>
<h2>Definição Avançada e Propriedades Opcionais</h2>
<p>Interfaces podem incluir propriedades opcionais e de apenas leitura, proporcionando controle fino sobre a estrutura esperada. Uma propriedade opcional é marcada com <code>?</code>, indicando que o objeto não precisa obrigatoriamente fornecê-la. Propriedades de apenas leitura usam <code>readonly</code>, garantindo que não serão modificadas após a criação.</p>
<p>Também é possível definir assinaturas de métodos dentro da interface, especificando qual o retorno esperado e quais parâmetros o método deve aceitar. Isso cria contratos mais robustos quando você precisa garantir comportamentos específicos em classes ou funções que implementam a interface.</p>
<pre><code class="language-typescript"></code></pre>
<h2>Extensão de Interfaces</h2>
<p>A extensão de interfaces permite reutilizar e construir sobre interfaces já existentes, promovendo código DRY (Don't Repeat Yourself). Usando a palavra-chave <code>extends</code>, você cria uma nova interface que herda todas as propriedades e métodos de uma ou mais interfaces existentes, adicionando novas propriedades conforme necessário.</p>
<p>Uma interface pode estender múltiplas outras interfaces simultaneamente, criando estruturas complexas a partir de componentes menores e reutilizáveis. Isso é particularmente útil em aplicações grandes onde você tem conceitos base que são expandidos em diferentes contextos. A extensão também permite sobrescrever tipos: uma propriedade pode ser redefinida em uma interface derivada com um tipo mais específico.</p>
<pre><code class="language-typescript">// Interface base
interface Entidade {
readonly id: number;
dataCriacao: Date;
}
// Interface que estende Entidade
interface Usuario extends Entidade {
nome: string;
email: string;
verificarEmail(): Promise<boolean>;
}
// Interface que estende múltiplas interfaces
interface AdminDeSistema extends Usuario {
nivelAcesso: "admin" | "moderador" | "usuario";
permissoes: string[];
revogarPermissao(permissao: string): void;
}
// Implementação concreta
class Admin implements AdminDeSistema {
readonly id: number;
dataCriacao: Date;
nome: string;
email: string;
nivelAcesso: "admin" | "moderador" | "usuario";
permissoes: string[];
constructor(
id: number,
nome: string,
email: string,
nivelAcesso: "admin" | "moderador" | "usuario"
) {
this.id = id;
this.dataCriacao = new Date();
this.nome = nome;
this.email = email;
this.nivelAcesso = nivelAcesso;
this.permissoes = [];
}
async verificarEmail(): Promise<boolean> {
// Implementação da verificação
return true;
}
revogarPermissao(permissao: string): void {
this.permissoes = this.permissoes.filter(p => p !== permissao);
}
}
const admin = new Admin(1, "Carlos", "carlos@admin.com", "admin");
admin.permissoes = ["criar_usuarios", "deletar_usuarios"];
admin.revogarPermissao("deletar_usuarios");
console.log(admin.permissoes); // ["criar_usuarios"]</code></pre>
<h2>Declaration Merging em Interfaces</h2>
<p>Declaration merging (fusão de declarações) é um recurso exclusivo de TypeScript que permite declarar a mesma interface múltiplas vezes, e o compilador as combina automaticamente em uma única interface. Isso é especialmente útil quando você quer estender funcionalidades de tipos existentes ou quando trabalha com código que será integrado de múltiplas fontes.</p>
<p>Quando você declara a mesma interface duas vezes, as propriedades de ambas as declarações são combinadas. Isso funciona apenas com interfaces — classes e tipos não suportam merging. Um caso de uso prático é estender interfaces de bibliotecas externas sem modificar o código original, ou quando você tem múltiplos arquivos que constroem a mesma interface incrementalmente.</p>
<pre><code class="language-typescript"></code></pre>
<h3>Merging com Namespaces</h3>
<p>Declaration merging também funciona ao combinar interfaces com namespaces, permitindo organizar código em módulos lógicos. Essa técnica é comum quando você quer separar tipos relacionados em diferentes espaços de nome para melhor organização.</p>
<pre><code class="language-typescript">// Declarar um namespace com uma interface
namespace Configuracao {
export interface Banco {
host: string;
porta: number;
usuario: string;
senha: string;
}
}
// Declarar uma interface no escopo global com o mesmo nome
interface Configuracao {
ambiente: "producao" | "desenvolvimento";
}
// Agora você acessa ambas:
const configBanco: Configuracao.Banco = {
host: "localhost",
porta: 5432,
usuario: "admin",
senha: "senha123"
};
const config: Configuracao = {
ambiente: "desenvolvimento"
};</code></pre>
<h3>Estendendo Tipos Globais</h3>
<p>Um caso de uso prático do declaration merging é estender interfaces globais fornecidas por bibliotecas, como estender o objeto <code>Window</code> no navegador ou adicionar propriedades ao objeto <code>process</code> do Node.js.</p>
<pre><code class="language-typescript">// Estendendo a interface Window do navegador
declare global {
interface Window {
meuApp: {
versao: string;
inicializar(): void;
};
}
}
// Agora você pode usar:
window.meuApp = {
versao: "1.0.0",
inicializar() {
console.log("Aplicação iniciada");
}
};
// Sem declaration merging, TypeScript reclamaria que
// 'meuApp' não existe em Window</code></pre>
<h2>Conclusão</h2>
<p>Interfaces em TypeScript são muito mais que simples documentação: são contratos que garantem segurança de tipo e melhor manutenibilidade. A capacidade de estender interfaces permite construir hierarquias de tipos reutilizáveis e escaláveis, enquanto o declaration merging oferece flexibilidade para integrar e estender código de múltiplas fontes sem duplicação. Dominando esses três pilares — definição, extensão e merging — você terá ferramentas poderosas para escrever código TypeScript profissional e resiliente.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.typescriptlang.org/docs/handbook/2/objects.html" target="_blank" rel="noopener noreferrer">TypeScript Official Documentation - Interfaces</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-merging.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook - Declaration Merging</a></li>
<li><a href="https://effectivetypescript.com/" target="_blank" rel="noopener noreferrer">Effective TypeScript by Dan Vanderkam - Item 11: Use Type Compatibility to Understand Errors</a></li>
<li><a href="https://devblogs.microsoft.com/typescript/" target="_blank" rel="noopener noreferrer">Microsoft TypeScript Blog - Advanced Types</a></li>
<li><a href="https://blog.logrocket.com/typescript-interfaces-vs-types/" target="_blank" rel="noopener noreferrer">Deep Dive into TypeScript Interfaces - LogRocket Blog</a></li>
</ul>
<p><!-- FIM --></p>