Matrizes de objetos em TypeScript: tutorial passo a passo para quem está cansado de erros
\n\nVocê já escreveu em TypeScript e de repente recebeu um sublinhado vermelho da IDE ao tentar adicionar um objeto a uma matriz? Familiar, certo? A pergunta "How can I define an array of objects?" é uma das mais populares no Stack Overflow. E não é à toa: sem a tipagem correta de matrizes de objetos, seu código se torna uma fonte de bugs e dores de cabeça.
\n\nNeste tutorial, vamos abordar todas as formas de definir uma matriz de objetos em TypeScript — das simples às avançadas. Você aprenderá como evitar erros comuns, como usar interfaces e como tornar seu código não apenas funcional, mas também elegante. Vamos lá!
\n\nPor que simplesmente [] não funciona?
\n\nSuponha que você escreva:
\n\nlet users = [];\n\nTypeScript vê isso como never[] — uma matriz que nunca deve conter elementos. Tente adicionar um objeto a ela:
users.push({ name: 'Анна', age: 25 }); // Erro!\n\nA IDE gritará: "Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'never'." TypeScript não sabe o que você pretende armazenar na matriz, portanto, bloqueia qualquer adição.
\n\nA solução é especificar explicitamente o tipo da matriz. Vamos analisar todas as opções.
\n\nMétodo 1: Anotação de tipo básica — colchetes
\n\nA maneira mais simples e intuitiva é usar a sintaxe Tipo[]:
let users: { name: string; age: number }[] = [];\n\nusers.push({ name: 'Анна', age: 25 }); // ✅ Funciona\nusers.push({ name: 'Иван', age: 30 }); // ✅ Funciona\n\n\nAqui, estamos dizendo ao TypeScript: "Ei, esta é uma matriz de objetos, cada um com as propriedades name (string) e age (número)". Agora a IDE está satisfeita, o preenchimento automático funciona e os erros de tipo são detectados em tempo de compilação.
\n\nDesvantagem: se a estrutura do objeto for complexa, descrevê-la diretamente na anotação se torna complicado. Para esses casos, foram criadas as interfaces.
\n\nMétodo 2: Interfaces — seu melhor amigo
\n\nAs interfaces permitem extrair a descrição do objeto para uma entidade separada e reutilizá-la. Isso torna o código mais limpo e compreensível:
\n\ninterface User {\n id: number;\n name: string;\n age: number;\n email?: string; // propriedade opcional\n}\n\nlet users: User[] = [];\n\nusers.push({ id: 1, name: 'Анна', age: 25 });\nusers.push({ id: 2, name: 'Иван', age: 30, email: 'ivan@example.com' }); // ✅\n\n\nAgora, se você tentar adicionar um objeto sem o campo id ou com o tipo incorreto, o TypeScript emitirá um erro. As interfaces são especialmente úteis quando o mesmo tipo de objeto é usado em vários lugares.
E quanto ao type?
\n\nEm vez de interface, você pode usar type:
type User = {\n id: number;\n name: string;\n age: number;\n};\n\nlet users: User[] = [];\n\nA diferença entre interface e type é um tópico para um artigo separado. Para matrizes de objetos, ambas as opções podem ser usadas, mas interface é mais frequentemente aplicada para descrever formas de objetos.
Método 3: Sintaxe genérica Array<Type>
\n\nUma forma alternativa é usar genéricos:
\n\nlet users: Array<{ name: string; age: number }> = [];\n\n// Ou com interface:\nlet users: Array<User> = [];\n\n\nAmbas as sintaxes (Type[] e Array<Type>) funcionam da mesma forma. A escolha é uma questão de gosto e contexto. Pessoalmente, prefiro Type[] para tipos simples e Array<Type> para construções genéricas complexas. Mas o importante é ser consistente no projeto.
Método 4: Criando uma matriz com objetos iniciais
\n\nFrequentemente, a matriz precisa não apenas ser declarada, mas também preenchida imediatamente com dados. TypeScr