TypeScript Generics: escrevendo código flexível sem duplicação

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: por que sem generics o TypeScript perde metade da força?



Imagine que você é um arquiteto que projeta um prédio do zero toda vez, mesmo quando precisa apenas construir mais uma garagem igual. É mais ou menos assim que se sente um desenvolvedor que escreve a mesma função para números, strings e arrays, sem usar TypeScript generics. Parece familiar? Se você já domina os tipos básicos em TypeScript, mas sente que escreve código duplicado demais, este artigo é para você.



Generics são um mecanismo que permite criar componentes (funções, classes, interfaces) que funcionam com diferentes tipos, em vez de um único específico. Em vez de copiar código, você o escreve uma vez, e o tipo é inserido automaticamente. Neste artigo, vamos explorar como a programação genérica funciona em TypeScript, mostrar exemplos reais de código e dar dicas práticas que tornarão seu código mais limpo e seguro.



Somos a PythonLib, e hoje falamos sobre TypeScript porque o desenvolvimento frontend moderno é impensável sem ele. Vamos nessa!



O que são generics em TypeScript e para que servem?



Vamos começar com um exemplo simples. Suponha que você queira escrever uma função que retorna o argumento recebido (função identidade).



// Sem generics — é necessário usar anyfunction identity(arg: any): any {    return arg;}

// Ou escrever sobrecargas para cada tipofunction identityNumber(arg: number): number { return arg; }function identityString(arg: string): string { return arg; }


A primeira opção destrói a tipagem — você perde informações sobre o tipo. A segunda obriga a criar várias funções idênticas. Generics TypeScript resolvem esse problema de forma elegante:



function identity<T>(arg: T): T {    return arg;}

const num = identity<number>(42); // tipo numberconst str = identity('hello'); // tipo string (inferência de tipo)const bool = identity(true); // tipo boolean


O símbolo <T> é o parâmetro de tipo. Você pode nomeá-lo como quiser (frequentemente usam T, U, V), mas é melhor dar nomes significativos se houver muitos. Quando você chama a função, o TypeScript substitui o tipo real no lugar de T. Se o tipo não for especificado explicitamente, o compilador o infere automaticamente a partir do argumento.



Assim, os tipos genéricos (Generics) permitem manter a tipagem estrita onde antes era necessário usar any. Isso reduz a quantidade de bugs e torna o código autodocumentável.



Sintaxe dos generics: do simples ao complexo



Funções genéricas



Já vimos o exemplo básico. Vamos complicar: uma função que recebe um array e retorna seu primeiro elemento.



function getFirst<T>(arr: T[]): T | undefined {    return arr[0];}

const firstNumber = getFirst([1, 2, 3]); // number | undefinedconst firstString = getFirst(['a', 'b', 'c']); // string | undefined


Observe: T[] é uma abreviação de Array<T>. Você pode usar qualquer forma.



Interfaces genéricas



Interfaces com generics são uma ferramenta poderosa para descrever estruturas de dados. Por exemplo, uma resposta de API tipada:



interface ApiResponse<T> {    data: T;    status: number;    message: string;}

// Usoconst userResponse: ApiResponse<{ id: number; name: string }> = { data: { id: 1, name: 'Alice' }, status: 200, message: 'OK'};


Agora uma única interface pode descrever respostas para usuários, produtos, pedidos — basta inserir o tipo adequado.



Classes genéricas



Classes também podem ser genéricas. Um exemplo clássico é a fila (Queue):



c                

Blogs

Book Recommendations