Menengah6 menit baca

Cara Menghasilkan Tipe TypeScript dari Tabel DynamoDB

Di Postgres Anda akan meng-introspeksi information_schema dan menghasilkan tipe darinya. DynamoDB tidak punya padanannya — dan itu bukan fitur yang hilang, itu model datanya: DynamoDB sama sekali tidak menyimpan schema Item. Satu-satunya atribut yang diketahui layanan adalah yang dipakai di key. AttributeDefinitions milik DescribeTable eksplisit soal cakupannya sendiri: setiap entri "menjelaskan satu atribut dalam schema key tabel dan indeks" (AWS API reference) — lima puluh atribut lain di tabel Anda memang tidak tercatat di mana pun.

Jadi "menghasilkan tipe TypeScript dari DynamoDB" selalu berarti satu dari tiga hal: mendeklarasikan bentuknya sendiri, menurunkannya dari sebuah schema yang Anda tulis di kode, atau menginferensinya dari Item yang benar-benar ada.

Bagaimana cara mendapatkan tipe TypeScript untuk sebuah tabel DynamoDB?

Tidak ada API yang mengembalikan bentuk Item sebuah tabel — DescribeTable hanya tahu atribut key. Opsi Anda: menulis-tangan sebuah interface dan memvalidasi di boundary (sebuah schema Zod menjadikan tipe dan pemeriksaan runtime satu artefak), memakai library schema-first di mana schema yang Anda tulis menghasilkan tipenya, atau menginferensi bentuknya dari Item nyata — lewat skrip, atau dengan alat seperti DynoTable yang men-scan tabel dan mengekspor sebuah interface TypeScript, schema Zod, atau JSON Schema.

Metode 1: tulis-tangan interface + validasi di boundary

AWS SDK tidak bisa mengetik Item Anda untuk Anda. Document client v3 mengembalikan Item sebagai record tanpa tipe — setiap hasil GetCommand / QueryCommand secara efektif adalah Record<string, unknown> sampai Anda menegaskan sebaliknya. Sebuah cast as Order telanjang terkompilasi dengan baik dan berbohong saat runtime, itulah kenapa versi yang tangguh memasangkan interface dengan pemeriksaan 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 schema, dua pekerjaan: z.infer memberi Anda tipe statis, parse menangkap Item yang tidak cocok dengannya — yang di sebuah store schemaless adalah soal kapan, bukan jika. Kelemahannya sama gamblangnya: schema itu mendokumentasikan niat Anda, bukan tabel Anda. Tidak ada yang mencegah sebuah writer lama pernah menyimpan total sebagai string, dan tipe tulisan-tangan melenceng diam-diam seiring data berevolusi.

Jika Anda bekerja dari output API mentah (bukan Document client), ingat bentuk kabelnya adalah DynamoDB-JSON bertipe-tag ({"S": "..."}, {"N": "123"}) — lihat marshalling, dan gunakan konverter DynamoDB JSON untuk membolak-balik sebuah sampel antara bentuk kabel dan bentuk biasa sembari Anda menulis schema-nya.

Metode 2: library schema-first

Toolkit seperti ElectroDB dan DynamoDB-Toolbox menyerang masalah drift dari sisi tulis: Anda menulis sebuah schema entity di kode, dan library menurunkan tipe TypeScript-nya dan menegakkan bentuknya pada setiap pembacaan dan penulisan yang ia lakukan. Itu jaminan terkuat yang tersedia — tetapi perhatikan arahnya: Anda yang menulis schema; library tidak menemukannya. Mengarahkannya ke tabel yang sudah ada tetap berarti Anda me-reverse-engineer bentuk Item-nya sendiri lebih dulu, dan Item yang ditulis di luar library berada di luar jaminannya. Mereka bersinar pada single-table design greenfield di mana setiap entity melewati toolkit sejak hari pertama.

Metode 3: inferensi tipe dari Item nyata

Untuk tabel yang sudah ada, kebenaran dasarnya adalah datanya. Scan sebuah sampel, gabungkan bentuk-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 langsung menghantam versi naifnya:

  • Atribut sparse. Item DynamoDB dalam satu tabel bisa punya atribut yang berbeda-beda; sebuah atribut yang hadir di 80% Item adalah optional, bukan hilang. Lacak frekuensi per-atribut, bukan sekadar kehadirannya.
  • Entity campuran. Dalam sebuah single-table design, Item USER# dan ORDER# berbagi tabel — satu interface gabungan untuk keduanya tidak berguna. Partisi sampelnya berdasarkan atribut type dan pancarkan satu tipe per entity.
  • Tabrakan tipe. Atribut yang sama tersimpan sebagai N di sini dan S di sana adalah bug data yang nyata (dan umum) — angkat ia sebagai union alih-alih diam-diam memilih salah satu. Set tag lengkapnya ada di tipe data.
  • Sampel tetaplah sampel. Atribut yang hanya muncul di Item langka mungkin tidak ada di 5.000 pertama Anda — dan scan itu berbiaya read capacity apa pun hasilnya (query vs scan).

Inferensi satu-klik di DynoTable

Skrip inferensi itu — sampling, pelacakan frekuensi, path bersarang, pemisahan per-entity — sudah terpasang di panel Table stats milik DynoTable:

  1. Buka sebuah tabel, tekan tombol Stats (ikon bar-chart), dan klik Index table. DynoTable men-scan tabelnya sekali dengan progres live dan menemukan setiap atribut yang dibawa Item Anda — termasuk yang bersarang lewat path bertitik, seperti commonData.status — beserta tipenya dan apakah ia required atau optional di seluruh baris yang di-scan.
  2. Klik Export dan pilih format:
    • TypeScript — sebuah interface.
    • Zod — sebuah schema z.object(...) (kompatibel Standard-Schema).
    • JSON Schema — draft 2020-12.
  3. Salin ke clipboard atau simpan ke file.
Panel Table stats DynoTable: daftar field terindeks dengan tipe dan penanda required/optional, serta tombol Export schema.
Panel Table stats DynoTable: daftar field terindeks dengan tipe dan penanda required/optional, serta tombol Export schema.

Ekspornya jujur soal apa dirinya: setiap schema yang dihasilkan dibuka dengan catatan bahwa ia diinferensi dari Item yang di-sampling — titik awal yang kuat, bukan kontrak yang otoritatif. Optionality mencerminkan seberapa sering setiap atribut muncul saat pengindeksan, dan atribut primary-key selalu ditandai required. Pengindeksan menimbulkan biaya baca DynamoDB normal, dan Reindex menyegarkan gambarannya setelah data Anda berubah.

FAQ

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

Apa cara terbaik mengetik tabel produksi yang sudah ada? Inferensi dulu, lalu perkeras: sampling Item nyata (skrip atau ekspor terindeks DynoTable) untuk mendapatkan bentuk sebenarnya, tinjau, dan promosikan menjadi schema Zod milik sendiri atau entity library schema-first agar drift ke depan tertangkap di boundary.

Bagaimana menangani banyak tipe entity dalam satu tabel? Satu tipe per entity, tidak pernah satu tipe gabungan. Pisahkan sampelnya berdasarkan atribut type Anda (atau prefiks key) dan hasilkan interface terpisah untuk masing-masing — discriminated union dari semuanya adalah tipe tabel Anda.

Kenapa tipe hasil generate saya menyebut sebuah field wajib sebagai optional? Karena ada Item ter-sampling yang tidak memilikinya. Di store schemaless, optionality adalah observasi, bukan deklarasi — periksa apakah Item-Item itu baris legacy yang perlu di-backfill (lihat migrasi) atau memang atribut yang benar-benar opsional.

Apakah tipenya mencakup set dan binary DynamoDB? Sebuah konverter harus memilih representasi plain-JSON: set menjadi array dan binary menjadi string ter-encode — keunikan pemetaan yang sama yang dibahas di marshalling. Round-trip sebuah sampel lewat konverter DynamoDB JSON untuk melihat persis seperti apa atribut Anda di tiap sisi.

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

Diperbarui