Mapeo de esquemas a tipos
Comprenda cómo las definiciones de tablas se convierten en tipos de TypeScript.
Mapeo de esquemas a tipos es una lección gratuita de TypeScript Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de TypeScript Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de TypeScript Academy incluye 4 lecciones en total.
De la definición de una tabla al tipo de fila
Un ORM con seguridad de tipos permite describir una tabla de base de datos una sola vez y derivar automáticamente su tipo de fila de TypeScript. Nunca tendrá que escribir manualmente la estructura de la fila; esta se calcula a partir de las definiciones de las columnas.
En esta lección se utiliza una tabla pgTable al estilo de Drizzle como ejemplo principal.
Definición de una tabla
Una tabla es un objeto que asigna nombres de columnas a constructores de columnas. Cada constructor codifica un tipo SQL y modificadores como notNull o 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(),
});Inferencia de tipos de columna
Cada constructor de columna contiene un tipo fantasma que describe el valor que produce. serial e integer se corresponden con number, text con string y boolean con boolean.
El constructor también registra si la columna admite valores nulos.
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 la nulabilidad
El factor determinante más importante del tipo de fila es notNull(). Una columna que NO lo incluye se convierte en T | null en el tipo inferido, porque SQL permite NULL de forma predeterminada.
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 select frente a insert
El tipo de fila para leer (select) es diferente del tipo para escribir (insert). Al insertar, las columnas con valores predeterminados o autoincremento se vuelven opcionales.
import { InferInsertModel } from "drizzle-orm";
type NewUser = InferInsertModel<typeof users>;
// {
// id?: number; // serial has a default -> optional
// name: string;
// age?: number | null;
// isAdmin: boolean;
// }Cómo funciona la inferencia
Internamente, cada constructor de columnas es una clase genérica como PgColumn<{ data: number; notNull: true }>. Un tipo mapeado recorre cada clave de la tabla y lee esos indicadores.
// 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;
};Tipos enum y personalizados
Las columnas de unión de cadenas se asignan a uniones de literales, no simplemente a string. Esto significa que un valor de estado no válido provoca un error de compilación.
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 predeterminados
.default() hace que una columna sea opcional al insertar, pero hace que siga estando presente al seleccionar. El sistema de tipos codifica "tiene un valor predeterminado" para poder cambiar la opcionalidad solo cuando corresponde.
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 qué es importante
Como el tipo de fila se deriva, un cambio en el esquema actualiza automáticamente el tipo de cada resultado de consulta. Cambie el nombre de una columna y el compilador marcará cada referencia obsoleta. No existe una segunda fuente de verdad que pueda desincronizarse.
Un pequeño ejemplo de principio a fin
En conjunto: defina una sola vez, infiera el tipo y úselo como contrato para una función de repositorio.
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];
}Error común: olvidar notNull
Si olvida notNull() en una columna que en realidad es obligatoria, el tipo inferido se convierte en T | null y obliga a realizar comprobaciones de nulidad innecesarias en todo el código. Mantenga el esquema fiel a la realidad.
Comprobación rápida
Compruebe su comprensión de la correspondencia entre el esquema y los tipos.
Resumen
Ha aprendido que la definición de una tabla es la única fuente de verdad: los constructores de columnas contienen tipos fantasma, los tipos mapeados recorren la tabla para construir el tipo de fila, notNull() controla la nulabilidad y los modelos de select e insert difieren en la opcionalidad. Cambie el esquema y todos los tipos de resultado se actualizarán automáticamente.
Preguntas frecuentes
¿La lección «Mapeo de esquemas a tipos» es gratis?
Sí — el texto completo de «Mapeo de esquemas a tipos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de TypeScript Academy, actualiza a CoddyKit PRO. El curso de TypeScript Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Mapeo de esquemas a tipos»?
Comprenda cómo las definiciones de tablas se convierten en tipos de TypeScript. Practicas TypeScript Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar TypeScript Academy?
No se requiere experiencia previa. TypeScript Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Mapeo de esquemas a tipos»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de TypeScript Academy?
Sí. Cada lección de TypeScript Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Mapeo de esquemas a tipos
- Construcción de queries segura
- Inferencia de estructuras de resultados de queries
- Relaciones y joins con tipos