TypeScript Types
Understanding the generated TypeScript interfaces, input types, and utility types from the Laizy client generator.
TypeScript Types
The laizy generate command produces a complete type system from your schema. Every content model gets three interfaces: a read type, a create input type, and an update input type. These types power autocomplete, compile-time validation, and documentation for your content layer.
Generated Interface Categories
For each model in your schema, three interfaces are generated:
Model Interface (Read Type)
The full representation of a content entry, including system fields. This is what you get back from findMany() and findById().
Given this schema:
model BlogPost {
title: String {
required: true
maxLength: 200
}
content: String {
required: true
}
status: String {
default: "draft"
}
slug: String {
required: true
unique: true
}
}The generator produces:
export interface BlogPost {
title: string
content: string
status: string
slug: string
// System fields
id: string
createdAt: Date
updatedAt: Date
}All fields are non-optional in the read type because every stored entry has values for all fields (either explicitly set or filled with defaults).
Create Input Type
The interface for creating new content. Only includes user-defined fields, with optionality based on the required constraint. Fields with default values are excluded since they have a fallback.
export interface CreateBlogPostInput {
title: string // required: true, no default
content: string // required: true, no default
slug: string // required: true, no default
// 'status' is excluded because it has default: "draft"
}Rules for Create inputs:
| Constraint | Result in CreateInput |
|---|---|
required: true, no default | Required field (no ?) |
required: true, has default | Excluded from interface |
No required (optional), no default | Optional field (?) |
No required, has default | Excluded from interface |
Update Input Type
The interface for partial updates. All fields are optional since you only send the fields you want to change.
export interface UpdateBlogPostInput {
title?: string
content?: string
status?: string
slug?: string
}Every user-defined field is optional with ?. System fields (id, createdAt, updatedAt) are never included in update inputs since they are managed by the system.
Type Mapping
Schema field types map to TypeScript types as follows:
| Schema Type | TypeScript Type | Example Value |
|---|---|---|
String | string | "Hello World" |
Int | number | 42 |
Float | number | 3.14 |
Boolean | boolean | true |
DateTime | Date | new Date("2024-01-15") |
Both Int and Float map to TypeScript's number type. The distinction between integers and floats is enforced at the schema validation level, not at the TypeScript type level.
System Fields
Every content model automatically includes three system fields. You do not define them in your schema, but they appear in the generated read interface:
// System fields added to every model
id: string // Unique identifier
createdAt: Date // Creation timestamp
updatedAt: Date // Last modification timestampSystem fields are:
- Present in the read type (e.g.,
BlogPost) - Absent from
CreateInputandUpdateInput(managed by the system) - Returned by all query methods (
findMany(),findById())
FindManyOptions
A generic utility type is generated for configuring list queries:
export interface FindManyOptions<T> {
where?: Partial<T>
select?: Partial<Record<keyof T, boolean>>
limit?: number
offset?: number
}This type is used by the findMany() method:
// Full type safety on the options
const posts = await client.blogPost.findMany({
limit: 10,
offset: 0,
});| Option | Type | Description |
|---|---|---|
where | Partial<T> | Filter criteria (field value matching) |
select | Partial<Record<keyof T, boolean>> | Field selection |
limit | number | Maximum results to return |
offset | number | Number of results to skip (for pagination) |
Multi-Model Example
When your schema has multiple models, each gets its own set of interfaces:
model Author {
name: String {
required: true
maxLength: 100
}
email: String {
required: true
unique: true
}
bio: String
}
model HeroSection {
badge: String
headline: String
subheading: String
ctaPrimary: String
ctaSecondary: String
}Generated types:
// Author types
export interface Author {
name: string
email: string
bio: string
id: string
createdAt: Date
updatedAt: Date
}
export interface CreateAuthorInput {
name: string // required
email: string // required
bio?: string // optional
}
export interface UpdateAuthorInput {
name?: string
email?: string
bio?: string
}
// HeroSection types
export interface HeroSection {
badge: string
headline: string
subheading: string
ctaPrimary: string
ctaSecondary: string
id: string
createdAt: Date
updatedAt: Date
}
export interface CreateHeroSectionInput {
badge: string
headline: string
subheading: string
ctaPrimary: string
ctaSecondary: string
}
export interface UpdateHeroSectionInput {
badge?: string
headline?: string
subheading?: string
ctaPrimary?: string
ctaSecondary?: string
}Using Types in Your Code
Import types directly from the generated module:
import type { BlogPost, CreateBlogPostInput, Author } from './generated/laizy';
// Type-safe function signatures
async function getPublishedPosts(): Promise<BlogPost[]> {
return client.blogPost.findMany();
}
// Type-safe content creation
const newPost: CreateBlogPostInput = {
title: 'My New Post',
content: 'Post content here',
slug: 'my-new-post',
};The types are also available through the barrel export:
import type { BlogPost } from './generated/laizy';
// Equivalent to importing from './generated/laizy/types'Regeneration
The generated types are fully overwritten each time you run pnpm laizy generate. The files include a // DO NOT EDIT - This file is auto-generated header as a reminder.
If you need to extend the types, create your own interfaces that compose the generated ones:
import type { BlogPost } from './generated/laizy';
// Extend with your own fields
interface BlogPostWithComments extends BlogPost {
comments: Comment[];
}Next Steps
- Queries -- How to use
findMany(),findById(), andcount() - Client Overview -- Setup and architecture of the generated client
- Generate Command -- CLI command reference for code generation