Cómo generar tipos de TypeScript a partir de una tabla de DynamoDB
En Postgres introspeccionarías information_schema y generarías los tipos a
partir de él. DynamoDB no tiene equivalente — y no es una funcionalidad que
falte, es el modelo de datos: DynamoDB no almacena ningún schema de
elementos. Los únicos atributos que el servicio conoce son los que se usan en
las claves. Las AttributeDefinitions de DescribeTable son explícitas sobre
su propio alcance: cada entrada "describe un atributo del schema de claves de
la tabla y los índices"
(referencia de la API de AWS) —
los otros cincuenta atributos de tu tabla simplemente no están registrados en
ninguna parte.
Así que "generar tipos de TypeScript desde DynamoDB" siempre significa una de tres cosas: declarar la forma tú mismo, derivarla de un schema que escribes en código, o inferirla de los elementos que realmente existen.
¿Cómo obtengo tipos de TypeScript para una tabla de DynamoDB?
No hay ninguna API que devuelva la forma de los elementos de una tabla —
DescribeTable solo conoce los atributos de las claves. Tus opciones: escribir
a mano una interface y validar en la frontera (un schema de Zod convierte los
tipos y la comprobación en tiempo de ejecución en un solo artefacto), usar una
librería schema-first donde el schema que escribes produce los tipos, o
inferir la forma a partir de elementos reales — con un script, o con una
herramienta como DynoTable que escanea la tabla y exporta una
interface de TypeScript, un schema de Zod o un JSON Schema.
- Método 1: escribir la interface a mano (+ Zod en la frontera)
- Método 2: librerías schema-first (tipos desde un schema que escribes)
- Método 3: inferir desde los propios datos
Método 1: escribir la interface a mano + validar en la frontera
El SDK de AWS no puede tipar tus elementos por ti. El Document client v3
devuelve los elementos como registros sin tipo — cada resultado de
GetCommand / QueryCommand es en la práctica Record<string, unknown>
hasta que tú afirmes lo contrario. Un simple cast as Order compila sin
problema y miente en tiempo de ejecución, y por eso la versión robusta empareja
la interface con una comprobación en tiempo de ejecución:
import {z} from 'zod';
const Order = z.object({
PK: z.string(), // ORDER#<id>
SK: z.string(), // META
status: z.enum(['open', 'shipped', 'cancelled']),
total: z.number(),
couponCode: z.string().optional() // sparse attribute
});
type Order = z.infer<typeof Order>;
const {Item} = await doc.send(new GetCommand({TableName: 'Orders', Key: key}));
const order = Order.parse(Item); // typed AND verifiedUn schema, dos trabajos: z.infer te da el tipo estático, parse atrapa el
elemento que no coincide con él — lo cual, en un almacén sin schema, es un
cuándo, no un si. La pega es igual de clara: el schema documenta tu
intención, no tu tabla. Nada impide que un escritor antiguo haya almacenado
total como cadena, y los tipos escritos a mano se desvían en silencio a
medida que los datos evolucionan.
Si trabajas con la salida cruda de la API (sin Document client), recuerda que
el formato de cable es DynamoDB-JSON con etiquetas de tipo ({"S": "..."},
{"N": "123"}) — consulta marshalling, y
usa el conversor de DynamoDB JSON para
alternar una muestra entre la forma de cable y la forma plana mientras escribes
el schema.
Método 2: librerías schema-first
Toolkits como ElectroDB y DynamoDB-Toolbox atacan el problema de la deriva desde el lado de la escritura: escribes un schema de entidad en código, y la librería deriva los tipos de TypeScript y aplica la forma en cada lectura y escritura que realiza. Es la garantía más fuerte disponible — pero fíjate en la dirección: tú escribes el schema; la librería no lo descubre. Apuntar una a una tabla existente sigue significando hacer ingeniería inversa de las formas de los elementos tú mismo primero, y los elementos escritos fuera de la librería quedan fuera de sus garantías. Brillan en diseños de tabla única nuevos donde cada entidad pasa por el toolkit desde el primer día.
Método 3: inferir los tipos a partir de elementos reales
Para una tabla existente, la verdad de referencia son los datos. Escanea una muestra y une las formas:
const seen = new Map<string, Set<string>>(); // attr -> observed types
let count = 0;
let key: Record<string, unknown> | undefined;
do {
const page = await doc.send(new ScanCommand({TableName: 'Orders', ExclusiveStartKey: key}));
for (const item of page.Items ?? []) {
count++;
for (const [attr, value] of Object.entries(item)) {
const t = Array.isArray(value) ? 'array' : typeof value;
(seen.get(attr) ?? seen.set(attr, new Set()).get(attr)!).add(t);
}
}
key = page.LastEvaluatedKey;
} while (key && count < 5000);
// emit: attribute -> type union, optional if seen in < count itemsTrampas del mundo real con las que la versión ingenua choca de inmediato:
- Atributos dispersos. Los elementos de DynamoDB de una misma tabla pueden
tener atributos distintos; un atributo presente en el 80% de los elementos es
optional, no inexistente. Registra la frecuencia por atributo, no solo la presencia. - Entidades mezcladas. En un
diseño de tabla única, los elementos
USER#yORDER#comparten la tabla — una interface fusionada para ambos es inútil. Particiona la muestra por el atributo de tipo y emite un tipo por entidad. - Colisiones de tipo. El mismo atributo almacenado como
Naquí ySallá es un bug de datos real (y común) — hazlo aflorar como una unión en lugar de elegir uno en silencio. El conjunto completo de etiquetas está en tipos de datos. - Una muestra es una muestra. Los atributos que solo aparecen en elementos raros pueden no estar en tus primeros 5.000 — y el scan cuesta capacidad de lectura de todos modos (query vs scan).
Inferencia con un clic en DynoTable
Ese script de inferencia — muestreo, seguimiento de frecuencias, rutas anidadas, la separación por entidad — está integrado en el panel de estadísticas de tabla de DynoTable:
- Abre una tabla, pulsa el botón de Estadísticas (el icono de gráfico de
barras) y haz clic en Indexar tabla. DynoTable escanea la tabla una vez
con progreso en vivo y descubre cada atributo que llevan tus elementos —
incluidos los anidados por ruta con puntos, como
commonData.status— con su tipo y si fue obligatorio u opcional entre las filas escaneadas. - Haz clic en Exportar y elige un formato:
- TypeScript — una
interface. - Zod — un schema
z.object(...)(compatible con Standard Schema). - JSON Schema — draft 2020-12.
- TypeScript — una
- Cópialo al portapapeles o guárdalo en un archivo.

La exportación es honesta sobre lo que es: cada schema generado empieza con una nota de que fue inferido a partir de los elementos muestreados — un punto de partida sólido, no un contrato autoritativo. La opcionalidad refleja la frecuencia con la que apareció cada atributo durante la indexación, y los atributos de la clave principal siempre se marcan como obligatorios. Indexar incurre en costes de lectura normales de DynamoDB, y Reindexar refresca la imagen cuando tus datos cambian.
Preguntas frecuentes
¿Puedo generar tipos desde DescribeTable?
Solo para los atributos de las claves. AttributeDefinitions cubre el schema
de claves de la tabla y los índices — el servicio no almacena nada más sobre
tus elementos, así que no hay un schema del lado del servidor que
introspeccionar.
¿Cuál es la mejor forma de tipar una tabla de producción existente? Primero inferir, luego endurecer: muestrea los elementos reales (con un script o la exportación indexada de DynoTable) para obtener la forma real, revísala y promuévela a un schema de Zod de tu propiedad o a una entidad de librería schema-first, de modo que la deriva futura se atrape en la frontera.
¿Cómo manejo varios tipos de entidad en una misma tabla? Un tipo por entidad, nunca un tipo fusionado. Separa la muestra por tu atributo de tipo (o prefijo de clave) y genera una interface separada para cada uno — la unión discriminada de esas es el tipo de tu tabla.
¿Por qué mis tipos generados dicen que un campo obligatorio es opcional? Porque algún elemento muestreado no lo tenía. En un almacén sin schema la opcionalidad es una observación, no una declaración — comprueba si esos elementos son filas antiguas que rellenar (consulta migraciones) o un atributo genuinamente opcional.
¿Cubren los tipos los conjuntos y los binarios de DynamoDB? Un conversor tiene que elegir representaciones en JSON plano: los conjuntos se convierten en arrays y los binarios en una cadena codificada — las mismas peculiaridades de mapeo que se cubren en marshalling. Pasa una muestra de ida y vuelta por el conversor de DynamoDB JSON para ver exactamente cómo se ven tus atributos en cada lado.
Deja de adivinar la forma de tu tabla — descarga DynoTable, indexa la tabla y exporta un TypeScript, Zod o JSON Schema en un clic.


