Pular para o conteúdoPedro Farbo
Lição 5 / 525 min

Introdução aos Genéricos

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 length

Gené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 existe

Default 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

  1. Use nomes descritivos - TItem, TKey, TValue são melhores que T, K, V
  2. Não abuse - se um tipo específico resolve, use-o
  3. Documente constraints - explique por que a restrição existe
  4. 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.

Gostou do conteúdo? Sua contribuição ajuda a manter tudo online e gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e