0Pricing
TypeScript Academy · Aula

Mapeamento de Esquema para Tipo

Entenda como definições de tabelas se tornam tipos TypeScript.

Mapeamento de Esquema para Tipo é uma aula grátis de TypeScript Academy no CoddyKit. Esta é a aula 1 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 TypeScript Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de TypeScript Academy inclui 4 aulas no total.

Da definição da tabela ao tipo da linha

Um ORM com segurança de tipos permite descrever uma tabela de banco de dados uma única vez e derivar automaticamente seu tipo de linha em TypeScript. Você nunca precisa escrever manualmente o formato da linha; ele é calculado a partir das definições das colunas.

Nesta lição, usamos um pgTable no estilo Drizzle como exemplo contínuo.

Definindo uma tabela

Uma tabela é um objeto que mapeia nomes de colunas para construtores de colunas. Cada construtor codifica um tipo SQL e modificadores como notNull ou primaryKey.

import { pgTable, serial, text, integer, boolean } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
  age: integer("age"),
  isAdmin: boolean("is_admin").notNull(),
});

Inferência do tipo da coluna

Cada construtor de coluna carrega um tipo fantasma que descreve o valor que ele produz. serial e integer correspondem a number, text corresponde a string, e boolean corresponde a boolean.

O construtor também acompanha se a coluna aceita nulo.

import { InferSelectModel } from "drizzle-orm";

// Row type inferred from the table above
type User = InferSelectModel<typeof users>;
// {
//   id: number;
//   name: string;
//   age: number | null;   // not notNull -> nullable
//   isAdmin: boolean;
// }

notNull Controla a Nulabilidade

O fator mais importante para determinar o tipo da linha é notNull(). Uma coluna SEM isso se torna T | null no tipo inferido, porque o SQL permite NULL por padrão.

const posts = pgTable("posts", {
  id: serial("id").primaryKey(),
  title: text("title").notNull(),  // string
  subtitle: text("subtitle"),      // string | null
});

type Post = InferSelectModel<typeof posts>;
// { id: number; title: string; subtitle: string | null }

Modelos de Seleção e Inserção

O tipo da linha para leitura (seleção) é diferente do tipo para escrita (inserção). Na inserção, as colunas com valores padrão ou incremento automático se tornam opcionais.

import { InferInsertModel } from "drizzle-orm";

type NewUser = InferInsertModel<typeof users>;
// {
//   id?: number;        // serial has a default -> optional
//   name: string;
//   age?: number | null;
//   isAdmin: boolean;
// }

Como a Inferência Funciona

Internamente, cada construtor de coluna é uma classe genérica como PgColumn<{ data: number; notNull: true }>. Um tipo mapeado percorre cada chave da tabela e lê essas sinalizações.

// Simplified mental model of the inference
type InferRow<T> = {
  [K in keyof T]: T[K] extends { _: { data: infer D; notNull: infer N } }
    ? N extends true ? D : D | null
    : never;
};

Enumerações e Tipos Personalizados

As colunas de união de cadeias de caracteres são mapeadas para uniões literais, não apenas para string. Isso significa que um valor de status inválido gera um erro de compilação.

import { pgEnum } from "drizzle-orm/pg-core";

export const roleEnum = pgEnum("role", ["user", "admin", "owner"]);

export const members = pgTable("members", {
  id: serial("id").primaryKey(),
  role: roleEnum("role").notNull(), // "user" | "admin" | "owner"
});

Valores Padrão

.default() torna uma coluna opcional na inserção, mas a mantém presente na seleção. O sistema de tipos codifica a informação de que ela "possui valor padrão" para alterar a opcionalidade somente quando apropriado.

const events = pgTable("events", {
  id: serial("id").primaryKey(),
  createdAt: text("created_at").notNull().default("now()"),
});
// Select: createdAt is string
// Insert: createdAt is optional (default fills it)

Por Que Isso Importa

Como o tipo da linha é derivado, uma alteração no esquema atualiza automaticamente o tipo de cada resultado de consulta. Renomeie uma coluna e o compilador sinalizará todas as referências desatualizadas. Não há uma segunda fonte de verdade que possa divergir.

Um Pequeno Exemplo de Ponta a Ponta

Juntando tudo: defina uma vez, infira o tipo e use-o como contrato para uma função de repositório.

type User = InferSelectModel<typeof users>;

async function findUser(id: number): Promise<User | undefined> {
  // db.query returns rows already typed as User
  const rows = await db.select().from(users).where(eq(users.id, id));
  return rows[0];
}

Armadilha: Esquecer notNull

Se você esquecer notNull() em uma coluna que é realmente obrigatória, o tipo inferido se torna T | null e força verificações de nulo desnecessárias em todo o seu código. Mantenha o esquema fiel à realidade.

Verificação Rápida

Teste sua compreensão do mapeamento entre esquema e tipo.

Recapitulação

Você aprendeu que uma definição de tabela é a fonte única da verdade: os construtores de coluna carregam tipos fantasma, os tipos mapeados percorrem a tabela para construir o tipo da linha, notNull() controla a nulabilidade, e os modelos de seleção e inserção diferem quanto à opcionalidade. Altere o esquema e todos os tipos de resultado acompanharão a mudança automaticamente.

Perguntas Frequentes

A aula “Mapeamento de Esquema para Tipo” é grátis?

Sim — o texto completo de “Mapeamento de Esquema para Tipo” é 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 TypeScript Academy, atualize para CoddyKit PRO. O curso de TypeScript Academy inclui 4 aulas no total.

O que vou aprender em “Mapeamento de Esquema para Tipo”?

Entenda como definições de tabelas se tornam tipos TypeScript. Você pratica TypeScript 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 TypeScript Academy?

Nenhuma experiência prévia é necessária. TypeScript 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 1 de 4.

Quanto tempo leva a aula “Mapeamento de Esquema para Tipo”?

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 TypeScript Academy?

Sim. Cada aula de TypeScript 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. Mapeamento de Esquema para Tipo
  2. Construção de Consultas com Segurança de Tipos
  3. Inferindo Estruturas de Resultados de Consultas
  4. Relações e Junções com Tipos
← Voltar para TypeScript Academy