0Pricing
React Academy · Aula

Componentes genéricos e tipos utilitários

Escreva componentes genéricos reutilizáveis e use PropsWithChildren, ComponentProps e Omit.

Componentes genéricos e tipos utilitários é uma aula grátis de React Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de React Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de React Academy inclui 4 aulas no total.

Por que usar componentes genéricos?

Componentes genéricos se adaptam a diferentes tipos de dados mantendo a segurança completa de tipos: uma lista, seleção ou tabela tipada que funciona com qualquer estrutura de dados.

Uma lista genérica simples

Use um parâmetro de tipo T na função para criar um componente de lista que renderiza itens de qualquer tipo.

interface ListProps<T> {
  items: T[];
  renderItem: (item: T, index: number) => React.ReactNode;
  keyExtractor: (item: T) => string;
}

function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        <li key={keyExtractor(item)}>{renderItem(item, i)}</li>
      ))}
    </ul>
  );
}

Restringindo tipos genéricos

Use extends para adicionar restrições, permitindo que o TypeScript saiba quais propriedades o tipo deve ter.

interface SelectProps<T extends { id: string; label: string }> {
  options: T[];
  value: T | null;
  onChange: (option: T) => void;
}

function Select<T extends { id: string; label: string }>(
  { options, value, onChange }: SelectProps<T>
) {
  return (
    <select value={value?.id} onChange={e => onChange(options.find(o => o.id === e.target.value)!)}>
      {options.map(o => <option key={o.id} value={o.id}>{o.label}</option>)}
    </select>
  );
}

PropsWithChildren

React.PropsWithChildren<P> adiciona children?: React.ReactNode a qualquer tipo de propriedades — útil para componentes de agrupamento.

function Card({ title, children }: React.PropsWithChildren<{ title: string }>) {
  return (
    <div className="card">
      <h2>{title}</h2>
      {children}
    </div>
  );
}

ComponentProps

React.ComponentProps<typeof Component> extrai as propriedades de um componente existente, sendo útil quando você deseja estendê-lo ou envolvê-lo.

import { Button } from './Button';

type ExtendedButtonProps = React.ComponentProps<typeof Button> & {
  loading?: boolean;
};

function LoadingButton({ loading, children, ...props }: ExtendedButtonProps) {
  return (
    <Button {...props} disabled={loading || props.disabled}>
      {loading ? <Spinner /> : children}
    </Button>
  );
}

ComponentPropsWithoutRef

React.ComponentPropsWithoutRef<'input'> extrai as propriedades de um elemento HTML sem a propriedade ref — ideal para envolver elementos HTML.

type InputProps = React.ComponentPropsWithoutRef<'input'> & {
  label: string;
  error?: string;
};

function FormInput({ label, error, ...inputProps }: InputProps) {
  return (
    <div>
      <label>{label}</label>
      <input {...inputProps} />
      {error && <span className="error">{error}</span>}
    </div>
  );
}

Omitir e selecionar

Use Omit<T, Keys> para remover propriedades específicas e Pick<T, Keys> para manter apenas propriedades específicas de um tipo existente.

interface UserCardProps {
  id: string;
  name: string;
  email: string;
  avatar: string;
  role: string;
}

// Only expose non-sensitive fields:
type PublicUserCardProps = Omit<UserCardProps, 'email' | 'role'>;
// Or pick exactly what you need:
type AvatarProps = Pick<UserCardProps, 'name' | 'avatar'>;

Parcial e obrigatório

Partial<T> torna todas as propriedades opcionais, sendo útil para formulários de atualização. Required<T> torna todas as propriedades obrigatórias.

interface UserFormData { name: string; email: string; bio: string; }

// For update: only send changed fields
type UserUpdatePayload = Partial<UserFormData>;

// For create: all fields are mandatory
type UserCreatePayload = Required<UserFormData>;

Record para dicionários tipados

Record<Keys, Value> cria um tipo de objeto com tipos de chave específicos, sendo útil para mapas de consulta e traduções.

type Status = 'idle' | 'loading' | 'success' | 'error';

const statusLabels: Record<Status, string> = {
  idle: 'Ready',
  loading: 'Loading...',
  success: 'Done!',
  error: 'Something went wrong',
};

ReturnType para tipos de ganchos

Use ReturnType<typeof useMyHook> para inferir o tipo de retorno de um gancho personalizado sem duplicar o tipo manualmente.

function useCounter(initial: number) {
  const [count, setCount] = useState(initial);
  return { count, increment: () => setCount(c => c + 1) };
}

type CounterHook = ReturnType<typeof useCounter>;
// { count: number; increment: () => void }

Componente de tabela genérico

Uma tabela de dados totalmente segura quanto aos tipos, que funciona com qualquer estrutura de linha, infere as chaves das colunas e ainda oferece preenchimento automático.

interface Column<T> {
  key: keyof T;
  header: string;
  render?: (value: T[keyof T], row: T) => React.ReactNode;
}

function DataTable<T extends object>({ data, columns }: { data: T[]; columns: Column<T>[] }) {
  return (
    <table>
      <thead><tr>{columns.map(c => <th key={String(c.key)}>{c.header}</th>)}</tr></thead>
      <tbody>{data.map((row, i) => (
        <tr key={i}>{columns.map(c => <td key={String(c.key)}>{c.render ? c.render(row[c.key], row) : String(row[c.key])}</td>)}</tr>
      ))}</tbody>
    </table>
  );
}

Verificação rápida

Qual tipo utilitário remove chaves especificadas de uma interface existente do TypeScript?

Recapitulação

Componentes genéricos usam parâmetros de tipo para manter a segurança de tipos em diferentes estruturas de dados. Tipos utilitários como Omit, Pick, Partial, ComponentProps e PropsWithChildren eliminam a duplicação manual de tipos e tornam as APIs dos componentes mais fáceis de compor.

Perguntas Frequentes

A aula “Componentes genéricos e tipos utilitários” é grátis?

Sim — o texto completo de “Componentes genéricos e tipos utilitários” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de React Academy, atualize para CoddyKit PRO. O curso de React Academy inclui 4 aulas no total.

O que vou aprender em “Componentes genéricos e tipos utilitários”?

Escreva componentes genéricos reutilizáveis e use PropsWithChildren, ComponentProps e Omit. Você pratica React Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar React Academy?

Nenhuma experiência prévia é necessária. React Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Componentes genéricos e tipos utilitários”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de React Academy?

Sim. Cada aula de React Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Tipando propriedades e tipos de retorno de componentes
  2. Tipando eventos e referências no TypeScript
  3. Componentes genéricos e tipos utilitários
  4. Tipando contextos e hooks personalizados
← Voltar para React Academy