Interfaces no TypeScript, da sintaxe a interface vs type
Interfaces no TypeScript
Interface no TypeScript: sintaxe, extends, merging e vs type | We.Inc
Monte uma interface campo a campo, veja o type alias correspondente e aprenda membros opcionais e readonly, extends, declaration merging e quando um type alias é a melhor escolha.
Uma interface dá nome ao formato de um objeto: quais propriedades ele tem e de que tipo é cada uma. Marque uma propriedade como opcional com ? e como imutável com readonly, construa sobre outro formato com extends e reabra o mesmo nome para mesclar mais membros. Interfaces não deixam rastro no JavaScript compilado; elas só orientam o verificador.
Sintaxe de interface em resumo
Você quer
Escreva
Uma propriedade obrigatória
name: string;
Uma propriedade opcional
nickname?: string;
Uma propriedade que não pode ser reatribuída
readonly id: number;
Um método
greet(other: User): string;
Qualquer quantidade de chaves string
[key: string]: number;
Reaproveitar outro formato
interface Admin extends User { ... }
Combinar vários formatos
interface A extends B, C { ... }
Adicione campos no gerador abaixo, marque opcional ou readonly e copie a interface ou o type alias equivalente. As seções seguintes tratam de extends, merging e dos poucos casos em que a escolha entre interface e type realmente faz diferença.
Dê um nome à interface e, se ela se basear em outra, digite esse nome no campo extends.
Adicione uma linha por propriedade, escolhendo o tipo e se ela é opcional ou readonly.
Leia a interface e o type alias que o gerador escreve a partir das mesmas linhas.
Copie qualquer uma das versões para o seu código.
Comece com interface para formatos de objeto e recorra a type quando precisar de uma union, uma tupla ou um mapped type. É a heurística que o próprio handbook do TypeScript sugere.
readonly só impede a reatribuição daquela propriedade. Objetos aninhados dentro dela ainda podem mudar, e nada é garantido em tempo de execução.
Uma propriedade opcional é lida como o seu tipo ou undefined, então verifique antes de usar ou dê um valor padrão na desestruturação.
Use nomes de interface no singular e descritivos, como Invoice ou CartItem. Um prefixo como IInvoice não acrescenta nada que o editor já não diga.
Perguntas frequentes
Devo usar interface ou type?
Para formatos de objeto os dois funcionam, e o handbook trata isso como questão de preferência pessoal, sugerindo interface até você precisar de um recurso que só type tem. Use type para unions, tuplas, primitivos e mapped ou conditional types; use interface quando quiser declaration merging.
O que é declaration merging?
Declarar uma interface com um nome que já existe adiciona membros a ela em vez de dar erro. Bibliotecas dependem disso para que você possa estender os tipos delas, por exemplo adicionando uma propriedade a Window. Um type alias com nome repetido é um erro.
O que acontece se duas interfaces mescladas derem tipos diferentes a uma propriedade?
O compilador acusa um erro. Com uma intersection de dois types, o conflito não é apontado na declaração; a propriedade vira never, o que aparece mais tarde e é mais difícil de rastrear.
Uma interface pode descrever uma função ou um array?
Sim. Uma call signature como (value: string): boolean descreve uma função, e uma index signature como [index: number]: string descreve um objeto parecido com array. Em casos simples, um type alias como type Check = (v: string) => boolean fica mais legível.
Interfaces existem em tempo de execução?
Não. Elas não geram código, então você não pode usar instanceof com uma interface nem listar as suas chaves. Verifique valores com um type guard em tempo de execução e anote o tipo de retorno dele com a interface.
extends versus intersections
interface Bear extends Animal copia todos os membros de Animal e permite adicionar outros. Um type alias faz o mesmo trabalho com uma intersection, type Bear = Animal & { honey: boolean }.
O handbook observa que extends pode ser mais rápido para o compilador e que acusa membros conflitantes bem onde são declarados. Intersections são práticas para juntar formatos que não são seus.
Opcional, readonly e index signatures
Um ponto de interrogação depois do nome torna a propriedade opcional, e o tipo de leitura dela inclui undefined. readonly bloqueia a atribuição àquela propriedade depois da criação, mas é só uma checagem em tempo de compilação.
Uma index signature, [key: string]: number, descreve dicionários cujas chaves você não consegue listar de antemão. As propriedades nomeadas na mesma interface precisam caber no tipo de valor da index signature.
Merging para estender tipos globais e de bibliotecas
Como as interfaces se mesclam, um arquivo de declaração pode adicionar os seus próprios campos a formatos nativos. Um caso comum é dar a Window uma propriedade que um script define, para que a leitura passe na checagem de tipos sem cast.
interface vs type alias
O que cada declaração consegue fazer
Recurso
type alias
Descrever o formato de um objeto
Sim
Sim
Adicionar membros redeclarando o nome
Sim (merging)
Não, erro de identificador duplicado
Construir sobre outro formato
Intersection com &
Union de formatos ou literais
Não
Sim
Dar nome a um primitivo ou tupla
Não
Sim
Mapped e conditional types
Não
Sim
Padrões que você vai escrever com frequência
Estendendo uma e várias interfaces
Admin recebe todos os membros de User mais os seus; Card combina dois formatos sem relação entre si.
Declaration merging em Window
Colocado em um arquivo .d.ts, isso faz window.appVersion passar na checagem de tipos em todo lugar.
Index signature e call signature
Scores aceita qualquer chave string; Validator descreve um valor que pode ser chamado.
Gerador de interfaces
Nome da interface
Extends (opcional)
Nome da propriedade {n}
Tipo da propriedade {n}
Opcional
Readonly
Remover propriedade {n}
Adicionar propriedade
Como interface
Como type alias
Copiar interface
Copiar type
Os nomes precisam começar com uma letra, $ ou _ e usar apenas letras, dígitos, $ ou _.