Skip to content

Typed models ​

ts
import { defineModel, infer, toSource, type Infer } from "@flattype/models";

const Address = defineModel({ city: "string", zip: "string" });

const User = defineModel({
  id: "number",                                  // "7" is coerced to 7
  name: "string",
  createdAt: "date",                             // reads created_at; ISO string or epoch ms → Date
  bio: "string?",                                // string | null, null when missing
  role: { type: "string", default: "viewer" },
  nickname: { type: "string", optional: true },  // left out when missing
  address: Address,                              // nested model
  tags: ["string"],                              // array
  orderId: "bigint",                             // exact 64-bit IDs (BigInt)
  avatar: "bytes?",                              // base64 → Uint8Array
});
type User = Infer<typeof User>;

User.parse(json);          // a JSON value or a Flat Notation string
User.parseList(json.data); // arrays, including Flat Notation tables
User.safeParse(json);      // { ok: true, value } | { ok: false, error }
User.serialize(user);      // back to API JSON (dates as ISO strings, bytes as base64)
User.encode(users);        // straight to Flat Notation

parse throws a ModelError listing every problem with its path, for example address.zip: Required and tags[1]: Expected string, got object. Unknown keys such as password_hash are dropped.

OptionDefaultEffect
keys"auto""auto" reads createdAt or created_at. "snake" also serializes back to snake_case. "exact" only reads the field name.
coercetrueConverts "42" → 42 and "true"/1 → true. Set false to require exact types.

Generate models from a real response:

ts
console.log(toSource(infer(await res.json()), "UsersPage"));
ts
import { defineModel, type Infer } from "@flattype/models";

export const UsersPageData = defineModel({
  id: "number",
  fullName: "string",
  createdAt: "date",
  bio: "string?",
  vip: { type: "boolean", optional: true },
}, { keys: "snake" });
export type UsersPageData = Infer<typeof UsersPageData>;

export const UsersPage = defineModel({
  page: "number",
  data: [UsersPageData],
});
export type UsersPage = Infer<typeof UsersPage>;

Released under the MIT License.