Introdução aos Genéricos
Genéricos permitem criar componentes que funcionam com diversos tipos, mantendo a segurança de tipos. São como "templates" que você pode customizar.
O Problema
Imagine que você quer criar uma função que retorna o primeiro elemento de um array:
typescript
// Sem genéricos - perde informação de tipofunction primeiroElemento(arr: any[]): any { return arr[0];} const num = primeiroElemento([1, 2, 3]); // tipo: anyconst str = primeiroElemento(["a", "b"]); // tipo: any // Perdemos a informação de que num é number e str é string!A Solução: Genéricos
typescript
function primeiroElemento<T>(arr: T[]): T { return arr[0];} const num = primeiroElemento([1, 2, 3]); // tipo: numberconst str = primeiroElemento(["a", "b"]); // tipo: string // TypeScript infere o tipo corretamente!O T é um parâmetro de tipo - um placeholder que será substituído pelo tipo real quando a função for chamada.
Sintaxe Básica
typescript
// Função genéricafunction identidade<T>(valor: T): T { return valor;} // Chamando - TypeScript infere o tipoidentidade("texto"); // T = stringidentidade(42); // T = number // Ou especificando explicitamenteidentidade<boolean>(true);Múltiplos Parâmetros de Tipo
typescript
function par<K, V>(chave: K, valor: V): [K, V] { return [chave, valor];} const resultado = par("idade", 30); // [string, number]const outro = par(1, true); // [number, boolean]Interfaces Genéricas
typescript
interface Caixa<T> { conteudo: T;} const caixaDeTexto: Caixa<string> = { conteudo: "Olá!"}; const caixaDeNumero: Caixa<number> = { conteudo: 42};Classes Genéricas
typescript
class Pilha<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 pilhaNumeros = new Pilha<number>();pilhaNumeros.push(1);pilhaNumeros.push(2);console.log(pilhaNumeros.pop()); // 2 const pilhaStrings = new Pilha<string>();pilhaStrings.push("a");pilhaStrings.push("b");Constraints (Restrições)
Limite quais tipos podem ser usados com extends:
typescript
// T deve ter a propriedade 'length'interface ComLength { length: number;} function tamanho<T extends ComLength>(item: T): number { return item.length;} tamanho("texto"); // OK - string tem lengthtamanho([1, 2, 3]); // OK - array tem lengthtamanho({ length: 5 }); // OK - objeto com length tamanho(42); // Erro! number não tem lengthGenéricos com keyof
typescript
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key];} const pessoa = { nome: "Pedro", idade: 30}; const nome = getProperty(pessoa, "nome"); // tipo: stringconst idade = getProperty(pessoa, "idade"); // tipo: number getProperty(pessoa, "endereco"); // Erro! "endereco" não existeDefault Types
typescript
interface ApiResponse<T = any> { data: T; status: number;} // Usa any como padrãoconst response1: ApiResponse = { data: "qualquer coisa", status: 200}; // Especifica o tipoconst response2: ApiResponse<Usuario> = { data: { nome: "Pedro", email: "pedro@email.com" }, status: 200};Exemplo Prático: Função de Fetch Tipada
typescript
async function fetchData<T>(url: string): Promise<T> { const response = await fetch(url); return response.json();} interface Usuario { id: number; nome: string; email: string;} // Uso tipadoconst usuario = await fetchData<Usuario>("/api/users/1");console.log(usuario.nome); // TypeScript sabe que é string!Utility Types com Genéricos
typescript
// Record - cria um tipo de objeto com chaves K e valores Vtype PageInfo = Record<string, { title: string; url: string }>; const pages: PageInfo = { home: { title: "Início", url: "/" }, about: { title: "Sobre", url: "/about" }}; // Extract - extrai tipos de uma uniontype T1 = Extract<"a" | "b" | "c", "a" | "f">; // "a" // Exclude - remove tipos de uma uniontype T2 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"Boas Práticas
- Use nomes descritivos -
TItem,TKey,TValuesão melhores queT,K,V - Não abuse - se um tipo específico resolve, use-o
- Documente constraints - explique por que a restrição existe
- Considere defaults - facilita o uso da API
Conclusão
Genéricos são uma ferramenta poderosa que permite escrever código reutilizável sem sacrificar a segurança de tipos.
Parabéns por completar todas as lições! 🎉
Agora você está pronto para fazer a prova final e conquistar seu certificado de conclusão do curso de Introdução ao TypeScript.