Intermediário7 min de leitura

Gere tipos TypeScript de DynamoDB

No Postgres você examinaria information_schema e geraria tipos a partir dele. DynamoDB não tem equivalente: DynamoDB não armazena nenhum esquema de item. Os únicos atributos service conhece são aqueles usados nas chaves. DescribeTable AttributeDefinitions é explícito sobre seu próprio escopo: cada entrada "descreve um atributo na tabela e no esquema de chave de índice" (referência AWS API) — os outros cinquenta atributos da sua tabela simplesmente não são registrados em lugar nenhum.

Portanto, "gerar tipos TypeScript a partir de DynamoDB" sempre significa uma de três coisas: declare a forma você mesmo, derive-a de um esquema que você criou código ou inferi-lo a partir dos itens que realmente existem.

Como obtenho tipos TypeScript para uma tabela DynamoDB?

Não há API que retorne a forma do item de uma tabela - DescribeTable só sabe os principais atributos. Suas opções: escrever à mão uma interface e validar em o limite (um esquema Zod torna os tipos e a verificação de tempo de execução um artefato), use uma biblioteca que prioriza o esquema, onde o esquema que você cria produz o tipos ou inferir a forma de itens reais - por script ou com uma ferramenta como DynoTable que verifica a tabela e exporta um TypeScript interface, esquema Zod ou esquema JSON.

Método 1: escrever a interface à mão + validar no limite

O SDK AWS não pode digitar seus itens para você. O cliente do documento v3 retorna itens como registros não digitados - cada resultado GetCommand / QueryCommand é efetivamente Record<string, desconhecido> até você afirmar o contrário. Um nu as Order cast compila bem e fica em tempo de execução, e é por isso que um rigoroso version emparelha a interface com uma verificação de tempo de execução:

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 verified

Um esquema, dois trabalhos: z.infer fornece o tipo estático, parse captura o item que não corresponde a ele - que em um armazenamento sem esquema é um quando, não um se. O problema é igualmente claro: o esquema documenta sua intenção, não sua tabela. Nada impede que um escritor antigo armazene o total como um string e tipos escritos à mão flutuam silenciosamente à medida que os dados evoluem.

Se você estiver trabalhando com saída API bruta (não cliente de documento), lembre-se do fio forma é marcada com o tipo DynamoDB-JSON ({"S": "..."}, {"N": "123"}) - veja marshalling e use o DynamoDB JSON converter para inverter uma amostra entre fio e forma simples enquanto você escreve o esquema.

Método 2: bibliotecas que priorizam o esquema

Kits de ferramentas como ElectroDB e DynamoDB-Toolbox atacam o problema de desvio do lado da gravação: você cria um esquema de entidade no código e a biblioteca deriva os tipos TypeScript e impõe a forma em cada leitura e gravação ele executa. Essa é a garantia mais forte disponível – mas observe o direção: você escreve o esquema; a biblioteca não descobre. Apontando um em uma tabela existente ainda significa fazer engenharia reversa nas formas dos itens você mesmo primeiro, e os itens escritos fora da biblioteca estão fora de seu garantias. Eles brilham no greenfield designs de tabela única onde cada entidade passa pelo kit de ferramentas desde o primeiro dia.

Método 3: inferir os tipos de itens reais

Para uma tabela existente, a verdade fundamental são os dados. Scan uma amostra, união das 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 items

Armadilhas do mundo real que a versão ingênua atinge imediatamente:

  • Atributos esparsos. DynamoDB itens em uma tabela podem ter diferentes atributos; um atributo presente em 80% dos itens é opcional, não faltando. Rastreie a frequência por atributo, não apenas a presença.
  • Entidades mistas. Em um design de tabela única, Os itens USER# e ORDER# compartilham a tabela — uma interface mesclada para ambos é inútil. Divida a amostra pelo atributo de tipo e emite um tipo por entidade.
  • Tipo colisões. O mesmo atributo armazenado como N aqui e S ali existe um bug de dados real (e comum) - mostre-o como uma união, em vez de silenciosamente escolhendo um. O conjunto completo de tags está em tipos de dados.
  • Uma amostra é uma amostra. Atributos que aparecem apenas em itens raros podem não esteja entre os primeiros 5.000 - e a digitalização custa capacidade de leitura de qualquer maneira (consulta vs verificação).

Inferência com um clique em DynoTable

Esse script de inferência – amostragem, rastreamento de frequência, caminhos aninhados, o divisão por entidade — é incorporada nas Estatísticas da tabela de DynoTable painel:

  1. Abra uma tabela, clique no botão Estatísticas (o ícone do gráfico de barras) e clique em Tabela de índice. DynoTable mostra a tabela com progresso e registros ao vivo os atributos que encontra - incluindo aqueles aninhados por caminho pontilhado, como commonData.status — com o tipo de cada um e se foi obrigatório ou opcional nas linhas verificadas. A varredura é limitada, então um atributo que aparece apenas em itens raros que podem estar faltando; veja Visão geral e indexação da tabela.
  2. Clique em Exportar e escolha um formato:
    • TypeScript — uma interface.
    • Zod — um esquema z.object(...) (compatível com esquema padrão).
    • JSON Esquema — rascunho 2020-12.
  3. Copie-o para a área de transferência ou salve-o em um arquivo.
Seção Indexação do DynoTable: a lista de campos indexados com tipos e sinalizadores obrigatórios/opcionais e o botão Exportar esquema.
Seção Indexação do DynoTable: a lista de campos indexados com tipos e sinalizadores obrigatórios/opcionais e o botão Exportar esquema.

Cada esquema gerado abre com um observe que foi inferido a partir dos itens da amostra - um ponto de partida forte ponto, não um contrato oficial. A opcionalidade reflete a frequência com que cada atributo apareceu durante a indexação e os atributos de chave primária são sempre marcado como obrigatório. A indexação incorre em custos normais de leitura DynamoDB e Reindexar atualiza a imagem depois que seus dados são alterados.

FAQ

Posso gerar tipos de DescribeTable? Somente para os atributos principais. AttributeDefinitions cobre a tabela e esquema de chave de índice – nada mais sobre seus itens é armazenado pelo serviço, portanto, não há esquema do lado do servidor para introspecção.

Qual é a melhor maneira de digitar uma tabela de produção existente? Inferir primeiro, depois endurecer: experimente os itens reais (script ou DynoTable exportação indexada) para obter a forma real, revise-a, e promovê-lo para um esquema Zod de propriedade manual ou uma entidade de biblioteca que prioriza o esquema, para que a deriva futura é capturada na fronteira.

Como lidar com vários tipos de entidade em uma tabela? Um tipo por entidade, nunca um tipo mesclado. Divida a amostra em seu tipo de atributo (ou prefixo de chave) e gere uma interface separada para cada um - a união discriminada deles é a sua tipo de tabela.

Por que meus tipos gerados dizem que um campo obrigatório é opcional? Porque algum item amostrado não o continha. Opcionalidade em uma loja sem esquema é uma observação, não uma declaração – verifique se esses itens são legados linhas para preencher (consulte migrações) ou um arquivo genuinamente atributo opcional.

Os tipos abrangem conjuntos DynamoDB e binários? Um conversor deve escolher representações JSON simples: conjuntos tornam-se arrays e binário se torna uma string codificada - as mesmas peculiaridades de mapeamento abordadas em empacotamento. Faça uma viagem de ida e volta através de uma amostra o conversor DynamoDB JSON para ver exatamente como são seus atributos em cada lado.

Pare de adivinhar o formato da sua tabela — download DynoTable, indexe o tabela e exporte um esquema TypeScript, Zod ou JSON com um clique.

Atualizado