Menengah6 menit baca

Hasilkan tipe TypeScript dari DynamoDB

Di Postgres Anda akan introspect information_schema dan menghasilkan tipe darinya. DynamoDB tidak punya padanan: DynamoDB tidak menyimpan skema item sama sekali. Satu-satunya atribut yang diketahui layanan adalah yang dipakai di key. AttributeDefinitions dari DescribeTable eksplisit soal cakupannya sendiri: setiap entri "describes one attribute in the table and index key schema" (referensi API AWS) — lima puluh atribut tabel Anda yang lain sekadar tidak dicatat di mana pun.

Jadi "hasilkan tipe TypeScript dari DynamoDB" selalu berarti salah satu dari tiga: deklarasikan bentuknya sendiri, turunkan dari skema yang Anda author di kode, atau infer dari item yang benar-benar ada.

Bagaimana saya mendapat tipe TypeScript untuk tabel DynamoDB?

Tidak ada API yang mengembalikan bentuk item tabel — DescribeTable hanya tahu atribut key. Opsi Anda: tulis interface dengan tangan dan validasi di batas (skema Zod menjadikan tipe dan cek runtime satu artefak), pakai library schema-first di mana skema yang Anda author menghasilkan tipe, atau infer bentuk dari item nyata — by skrip, atau dengan tool seperti DynoTable yang men-scan tabel dan mengekspor interface TypeScript, skema Zod, atau JSON Schema.

Method 1: tulis interface dengan tangan + validasi di batas

AWS SDK tidak bisa men-type item Anda untuk Anda. Document client v3 mengembalikan item sebagai record tanpa tipe — setiap hasil GetCommand / QueryCommand secara efektif Record<string, unknown> sampai Anda meng-assert sebaliknya. Cast as Order telanjang mengompilasi baik dan berbohong saat runtime, itulah mengapa versi ketat memasangkan interface dengan cek 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 verified

Satu skema, dua pekerjaan: z.infer memberi tipe statis, parse menangkap item yang tidak cocok — yang di store schemaless adalah kapan, bukan jika. Catch-nya sama polos: skema mendokumentasikan intent Anda, bukan tabel Anda. Tidak ada yang menghentikan writer lama menyimpan total sebagai string, dan tipe buatan tangan drift diam-diam saat data berevolusi.

Jika Anda bekerja dari output API mentah (non-Document-client), ingat bentuk wire adalah DynamoDB-JSON ber-type-tag ({"S": "..."}, {"N": "123"}) — lihat marshalling, dan pakai konverter DynamoDB JSON untuk membolak-balik sampel antara wire dan bentuk polos sambil Anda menulis skema.

Method 2: library schema-first

Toolkit seperti ElectroDB dan DynamoDB-Toolbox menyerang masalah drift dari sisi write: Anda author skema entity di kode, dan library menurunkan tipe TypeScript dan menegakkan bentuk pada setiap baca dan tulis yang dilakukannya. Itu jaminan terkuat yang tersedia — tetapi catat arahnya: Anda menulis skema; library tidak menemukannya. Mengarahkannya ke tabel yang sudah ada tetap berarti reverse-engineering bentuk item sendiri dulu, dan item yang ditulis di luar library di luar jaminannya. Mereka bersinar pada single-table design greenfield di mana setiap entity lewat toolkit dari hari pertama.

Method 3: infer tipe dari item nyata

Untuk tabel yang sudah ada, ground truth adalah data. Scan sampel, union bentuknya:

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

Jebakan dunia nyata yang segera ditabrak versi naif:

  • Atribut sparse. Item DynamoDB dalam satu tabel bisa punya atribut berbeda; atribut yang hadir pada 80% item adalah optional, bukan hilang. Lacak frekuensi per-atribut, bukan sekadar kehadiran.
  • Entity campuran. Di single-table design, item USER# dan ORDER# berbagi tabel — satu interface digabung untuk keduanya sia-sia. Partisi sampel by type attribute dan emit satu tipe per entity.
  • Tabrakan tipe. Atribut yang sama disimpan sebagai N di sini dan S di sana adalah bug data nyata (dan umum) — tampilkan sebagai union alih-alih diam-diam memilih satu. Set tag penuh di data types.
  • Sampel adalah sampel. Atribut yang hanya muncul pada item langka mungkin tidak ada di 5.000 pertama Anda — dan scan menelan kapasitas baca bagaimanapun (query vs scan).

Inferensi sekali klik di DynoTable

Skrip inferensi itu — sampling, pelacakan frekuensi, path nested, split per-entitas — sudah ada di dalam dialog tabel DynoTable:

  1. Buka tabel, tekan tombol Pengaturan di bilah alat tab, buka bagian Pengindeksan, lalu klik Index table. DynoTable mengambil sampel tabel dengan progres live dan mencatat atribut yang ditemukannya — termasuk yang nested by path bertitik, seperti commonData.status — dengan tipe masing-masing dan apakah required atau optional lintas baris yang di-scan. Scan dibatasi, jadi atribut yang hanya muncul di item langka bisa hilang; lihat Ikhtisar tabel dan pengindeksan.
  2. Klik Ekspor dan pilih format:
    • TypeScript — sebuah interface.
    • Zod — skema z.object(...) (kompatibel Standard-Schema).
    • JSON Schema — draft 2020-12.
  3. Salin ke clipboard atau simpan ke file.
Bagian Pengindeksan DynoTable: daftar field terindeks dengan tipe dan flag required/optional, serta tombol Export skema.
Bagian Pengindeksan DynoTable: daftar field terindeks dengan tipe dan flag required/optional, serta tombol Export skema.

Setiap skema yang dihasilkan dibuka dengan catatan bahwa ia diinfer dari item yang disampel — titik awal yang kuat, bukan kontrak otoritatif. Optionality mencerminkan seberapa sering tiap atribut muncul saat indexing, dan atribut primary key selalu ditandai required. Indexing menelan biaya baca DynamoDB normal, dan Index ulang menyegarkan gambaran setelah data Anda berubah.

FAQ

Bisakah saya menghasilkan tipe dari DescribeTable? Hanya untuk atribut key. AttributeDefinitions mencakup skema key tabel dan indeks — tidak ada yang lain tentang item Anda yang disimpan layanan, jadi tidak ada skema sisi server untuk di-introspect.

Apa cara terbaik men-type tabel produksi yang sudah ada? Infer dulu, lalu harden: sampel item nyata (skrip atau ekspor terindeks DynoTable) untuk mendapat bentuk aktual, tinjau, dan promosikan ke skema Zod yang dimiliki tangan atau entity library schema-first agar drift masa depan tertangkap di batas.

Bagaimana saya menangani banyak tipe entity dalam satu tabel? Satu tipe per entity, jangan pernah satu tipe digabung. Pecah sampel pada type attribute Anda (atau prefix key) dan hasilkan interface terpisah untuk masing-masing — discriminated union dari itu adalah tipe tabel Anda.

Mengapa tipe yang dihasilkan bilang field required adalah optional? Karena beberapa item sampel tidak memilikinya. Di store schemaless optionality adalah observasi, bukan deklarasi — cek apakah item itu baris legacy untuk di-backfill (lihat migrations) atau atribut yang benar-benar optional.

Apakah tipe mencakup set DynamoDB dan binary? Converter harus memilih representasi JSON polos: set menjadi array dan binary menjadi string ter-encode — quirk mapping yang sama dibahas di marshalling. Round-trip sampel lewat konverter DynamoDB JSON untuk melihat tepat seperti apa atribut Anda di tiap sisi.

Berhenti menebak bentuk tabel Anda — unduh DynoTable, indeks tabel, dan ekspor TypeScript, Zod, atau JSON Schema dalam satu klik.

Diperbarui