Como Gerar Tipos TypeScript a partir de uma Tabela DynamoDB
No Postgres você faria introspecção do information_schema e geraria os tipos a partir dele.
O DynamoDB não tem equivalente — e não é uma feature faltando, é o modelo de
dados: o DynamoDB não armazena nenhum schema de item. Os únicos atributos que o
serviço conhece são os usados em chaves. O AttributeDefinitions do DescribeTable
é explícito sobre o próprio escopo: cada entrada "descreve
um atributo no schema de chaves da tabela e dos índices"
(referência da API da AWS) —
os outros cinquenta atributos da sua tabela simplesmente não são registrados em lugar nenhum.
Então "gerar tipos TypeScript do DynamoDB" sempre significa uma de três coisas: declarar o formato você mesmo, derivá-lo de um schema que você escreve em código, ou inferi-lo dos itens que realmente existem.
Como obtenho tipos TypeScript para uma tabela DynamoDB?
Não existe API que retorne o formato dos itens de uma tabela — o DescribeTable só conhece
os atributos de chave. Suas opções: escrever uma interface à mão e validar na
fronteira (um schema Zod torna os tipos e a checagem de runtime um só
artefato), usar uma biblioteca schema-first onde o schema que você escreve produz os
tipos, ou inferir o formato de itens reais — por script, ou com uma ferramenta como o
DynoTable que escaneia a tabela e exporta uma interface TypeScript,
um schema Zod ou um JSON Schema.
- Método 1: escrever a interface à mão (+ Zod na fronteira)
- Método 2: bibliotecas schema-first (tipos de um schema que você escreve)
- Método 3: inferir dos próprios dados
Método 1: escreva a interface à mão + valide na fronteira
O AWS SDK não consegue tipar seus itens por você. O Document client v3 retorna
itens como registros sem tipo — todo resultado de GetCommand / QueryCommand é
efetivamente Record<string, unknown> até você afirmar o contrário. Um cast
seco de as Order compila numa boa e mente em runtime, e é por isso que a versão
robusta emparelha a interface com uma checagem de runtime:
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 verifiedUm schema, dois trabalhos: z.infer te dá o tipo estático, parse pega o
item que não bate com ele — o que em um armazenamento sem schema é um quando, não um
se. O porém é igualmente claro: o schema documenta a sua intenção, não
a sua tabela. Nada impede que um escritor antigo tenha armazenado total como
string, e tipos escritos à mão derivam silenciosamente conforme os dados evoluem.
Se você está trabalhando com a saída crua da API (sem Document client), lembre que o formato
de rede é DynamoDB-JSON com tags de tipo ({"S": "..."}, {"N": "123"}) — veja
marshalling, e use o
conversor DynamoDB JSON para alternar uma amostra
entre a forma de rede e a forma simples enquanto escreve o schema.
Método 2: bibliotecas schema-first
Toolkits como ElectroDB e DynamoDB-Toolbox atacam o problema do desvio pelo lado da escrita: você escreve um schema de entidade em código, e a biblioteca deriva os tipos TypeScript e impõe o formato em cada leitura e escrita que ela executa. Essa é a garantia mais forte disponível — mas note a direção: você escreve o schema; a biblioteca não o descobre. Apontar uma para uma tabela existente ainda significa fazer engenharia reversa dos formatos de item você mesmo primeiro, e itens escritos fora da biblioteca ficam fora das suas garantias. Elas brilham em single-table designs greenfield onde cada entidade passa pelo toolkit desde o primeiro dia.
Método 3: infira os tipos de itens reais
Para uma tabela existente, a verdade fundamental são os dados. Escaneie uma amostra, faça a união dos formatos:
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 itemsArmadilhas do mundo real que a versão ingênua encontra imediatamente:
- Atributos esparsos. Itens do DynamoDB em uma mesma tabela podem ter atributos
diferentes; um atributo presente em 80% dos itens é
optional, não ausente. Rastreie a frequência por atributo, não só a presença. - Entidades misturadas. Em um single-table design,
itens
USER#eORDER#compartilham a tabela — uma interface fundida para ambos é inútil. Particione a amostra pelo atributo de tipo e emita um tipo por entidade. - Colisões de tipo. O mesmo atributo armazenado como
Naqui eSali é um bug de dados real (e comum) — exponha-o como uma união em vez de silenciosamente escolher um. O conjunto completo de tags está em tipos de dados. - Uma amostra é uma amostra. Atributos que só aparecem em itens raros podem não estar nos seus primeiros 5.000 — e o scan custa capacidade de leitura de qualquer forma (query vs scan).
Inferência em um clique no DynoTable
Esse script de inferência — amostragem, rastreio de frequência, caminhos aninhados, a divisão por entidade — está embutido no painel Estatísticas da tabela do DynoTable:
- Abra uma tabela, aperte o botão Estatísticas (o ícone de gráfico de barras) e clique em
Indexar tabela. O DynoTable escaneia a tabela uma vez com progresso ao vivo e
descobre cada atributo que seus itens carregam — incluindo os aninhados por
caminho pontuado, como
commonData.status— com seu tipo e se ele foi obrigatório ou opcional entre as linhas escaneadas. - Clique em Exportar e escolha um formato:
- TypeScript — uma
interface. - Zod — um schema
z.object(...)(compatível com Standard-Schema). - JSON Schema — draft 2020-12.
- TypeScript — uma
- Copie para a área de transferência ou salve em um arquivo.

O export é honesto sobre o que é: cada schema gerado abre com uma nota de que foi inferido dos itens amostrados — um ponto de partida forte, não um contrato autoritativo. A opcionalidade reflete a frequência com que cada atributo apareceu durante a indexação, e atributos de chave primária são sempre marcados como obrigatórios. Indexar incorre em custos normais de leitura do DynamoDB, e Reindexar atualiza o retrato depois que seus dados mudarem.
FAQ
Posso gerar tipos a partir do DescribeTable?
Apenas para os atributos de chave. O AttributeDefinitions cobre o schema de chaves da
tabela e dos índices — nada mais sobre seus itens é armazenado pelo serviço,
então não existe schema no servidor para introspectar.
Qual é a melhor forma de tipar uma tabela de produção existente? Infira primeiro, endureça depois: amostre os itens reais (script ou o export indexado do DynoTable) para obter o formato real, revise-o, e promova-o a um schema Zod de sua propriedade ou a uma entidade de biblioteca schema-first para que desvios futuros sejam pegos na fronteira.
Como lido com múltiplos tipos de entidade em uma tabela? Um tipo por entidade, nunca um tipo fundido. Divida a amostra pelo seu atributo de tipo (ou prefixo de chave) e gere uma interface separada para cada — a união discriminada delas é o tipo da sua tabela.
Por que meus tipos gerados dizem que um campo obrigatório é opcional? Porque algum item amostrado não o tinha. Em um armazenamento sem schema, opcionalidade é uma observação, não uma declaração — verifique se esses itens são linhas legadas para backfill (veja migrações) ou um atributo genuinamente opcional.
Os tipos cobrem sets e binário do DynamoDB? Um conversor tem que escolher representações em JSON simples: sets viram arrays e binário vira uma string codificada — as mesmas peculiaridades de mapeamento cobertas em marshalling. Faça o round-trip de uma amostra pelo conversor DynamoDB JSON para ver exatamente como seus atributos ficam de cada lado.
Pare de adivinhar o formato da sua tabela — baixe o DynoTable, indexe a tabela e exporte um TypeScript, Zod ou JSON Schema em um clique.


