Generics em TypeScript: guia completo sobre genéricos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução a Generics em TypeScript



TypeScript é uma linguagem fortemente tipada que estende as capacidades do JavaScript adicionando tipagem estática. No entanto, um de seus recursos mais poderosos e flexíveis é o mecanismo de Generics. Se você já escreveu código que precisa funcionar com diferentes tipos de dados, mantendo a segurança de tipos, então Generics é exatamente o que você precisa.



Imagine que você está criando uma função universal que pode aceitar arrays de números, strings ou objetos. Sem generics, você teria que usar o tipo any (o que anula todos os benefícios do TypeScript) ou escrever funções separadas para cada tipo. Generics resolvem esse problema de forma elegante e segura. Neste artigo, vamos explorar o que são Generics, por que são necessários e como usá-los efetivamente em projetos reais.



O que são Generics e por que são necessários?



Generics é um mecanismo que permite criar componentes (funções, classes, interfaces) capazes de trabalhar com diferentes tipos de dados sem perder informações sobre os tipos. Em vez de fixar um tipo específico, você usa um parâmetro de tipo que é substituído no momento da chamada.



Problema sem Generics



Suponha que você queira escrever uma função que retorna o primeiro elemento de um array. Sem generics, isso poderia ser assim:



function getFirstElement(arr: any[]): any {  return arr[0];}

const num = getFirstElement([1, 2, 3]); // Tipo 'any' — perdemos a informaçãoconsole.log(num.toUpperCase()); // Erro em tempo de execução, mas TypeScript não reclama


Aqui usamos any, e o TypeScript não pode nos alertar que num é um número, não uma string. Isso leva a potenciais erros em tempo de execução.



Solução com Generics



Agora vamos reescrever a mesma função usando generics:



function getFirstElement<T>(arr: T[]): T {  return arr[0];}

const num = getFirstElement([1, 2, 3]); // Tipo 'number'const str = getFirstElement(['a', 'b', 'c']); // Tipo 'string'

// num.toUpperCase(); // Erro de compilação — TypeScript sabe que num é número


O símbolo <T> é o parâmetro de tipo. Ele funciona como um placeholder: quando chamamos a função com um array de números, T se torna number, e o valor retornado também recebe o tipo number. Dessa forma, mantemos a tipagem estrita sem perder flexibilidade.



Como usar Generics: cenários principais



Generics não são aplicados apenas em funções, mas também em classes, interfaces e tipos. Vamos considerar os cenários mais comuns.



Generics em funções



O caso mais simples e frequente são funções que trabalham com dados de diferentes tipos. Por exemplo, uma função para criar um par chave-valor:



function createPair<K, V>(key: K, value: V): { key: K; value: V } {  return { key, value };}

const pair = createPair('id', 123); // { key: string; value: number }console.log(pair.key.toUpperCase()); // Funciona// pair.key.toFixed(); // Erro — key é uma string


Aqui usamos dois parâmetros de tipo: K para a chave e V para o valor. O TypeScript infere automaticamente os tipos com base nos argumentos.



Generics em classes



Generics são excelentes para criar classes universais, como pilhas, filas ou armazenamentos de dados:



class Stack<T> {  private items: T[] = [];

push(item: T): void { this.items.push(item); }

pop(): T | undefined { return this.items.pop(); }

peek(): T | undefined { return this.items[this.items.length - 1]; }}

const numberStack = new Stack<number>();numberStack.push(10);numberStack.push(20);console.log(numberStack

Blogs

Book Recommendations