Se você usa any quando o TypeScript reclama, este artigo é para você. Generics são a ferramenta mais poderosa para criar componentes reutilizáveis e seguros.
O Que é um Generic?
Pense em uma função normal. Ela aceita argumentos (valores) e retorna um valor. Um Generic aceita tipos e retorna um tipo.
// Função Normal: Aceita valor, retorna valor
function echo(value: string): string {
return value;
}
// Generic: Aceita Tipo <T>, usa T para definir argumento e retorno
function echoGeneric<T>(value: T): T {
return value;
}
Agora echoGeneric funciona para string, number, objects, e o TS saberá exatamente o que sai dela.
Restrições (Constraints)
Às vezes, T pode ser qualquer coisa, mas você precisa garantir que ele tenha uma propriedade específica (ex: .length).
function logLength<T extends { length: number }>(item: T) {
console.log(item.length);
}
logLength("Ola"); // OK (String tem length)
logLength([1, 2]); // OK (Array tem length)
logLength(10); // ERRO! (Number não tem length)
Generics em React Props
Super comum ao criar componentes de Lista/Tabela flexíveis.
type ListProps<T> = {
items: T[];
renderItem: (item: T) => React.ReactNode;
};
export function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
Uso:
<List
items={users}
renderItem={(user) => <span>{user.name}</span>} // TS sabe que 'user' é do tipo User!
/>
Isso é a essência de bibliotecas robustas. Você escreve o componente uma vez, e ele se adapta a qualquer dado, mantendo o type-safety.