Show navigationHide navigation

Generated Types

The CMS auto-generates TypeScript types from cms/octocms.config.ts into cms/__generated__/. These provide concrete, readable interfaces with fully resolved reference fields — no unknown, no deeply nested conditional types.

Quick start#

bash
npm run types:gen     # Regenerate from cms/octocms.config.ts
npm run types:check   # Regenerate + fail if output differs (CI)

What is generated#

FileContents
cms/__generated__/types.ts<Collection>Fields and <Collection>Entry interfaces, EntryMap, AnyEntry
cms/__generated__/enums.tsCollectionName const object, COLLECTION_NAMES array, select option const objects, FieldFormat
cms/__generated__/content.d.tsRaw on-disk types (Raw<Collection>Fields / Raw<Collection>Entry) — before query() processing
cms/__generated__/index.tsBarrel re-export of types and enums

Usage with query()#

The query() API in octocms/query.ts uses the generated EntryMap for return types. Reference fields are resolved to concrete entry types:

typescript
import { query } from 'octocms/query';

const posts = await query('post').toArray();
//    ^? PostEntry[]

posts[0].fields.title;
//                ^? string

// Blog references resolve to PostEntry[], not unknown
const blog = await query('blog').first();
blog?.fields.posts;
//            ^? PostEntry[]

// Author → Role references are fully resolved
const authors = await query('author').toArray();
authors[0].fields.roles;
//                 ^? RoleEntry[]

Usage client-side (fetch)#

The generated types can be imported in any client or server component:

typescript
import type { PostEntry } from 'cms/__generated__';

const res = await fetch('/api/posts');
const posts: PostEntry[] = await res.json();
// Full autocomplete on posts[0].fields.title, etc.

Select option enums#

Select fields generate const objects for type-safe comparisons:

typescript
import { ItemCategoryOption } from 'cms/__generated__';

// Const object — use as values
if (item.fields.category === ItemCategoryOption.Featured) { ... }

// Type — use in signatures
function filterByCategory(cat: ItemCategoryOption) { ... }

Naming convention: {PascalCollection}{PascalField}Option.

Collection name enum#

typescript
import { CollectionName, COLLECTION_NAMES } from 'cms/__generated__';

// Const object — type-safe collection name access
query(CollectionName.Post).toArray();

// Array — iterate over all collection names
for (const name of COLLECTION_NAMES) { ... }

Raw content types (content.d.ts)#

For validating content JSON files locally (without the admin UI), import from content.d.ts:

typescript
import type { RawPostEntry } from 'cms/__generated__/content.d';

Key differences from resolved types:

  • Image fields: string (UUID) instead of ResolvedImageField
  • Reference fields: string (key or JSON-stringified array) instead of resolved entry types
  • Markdown fields: Omitted (stored in companion .md files, not in JSON)

How it works#

The generator reads cms/octocms.config.ts at build time and emits TypeScript interfaces. It:

  1. Validates the config (same rules as docs:gen plus reference/conditional/identifier checks)
  2. Maps each field format to its TypeScript type
  3. Resolves reference fields to concrete <Collection>Entry types (handles cycles via TypeScript forward references)
  4. Emits const objects for collection names and select options

Keeping types in sync#

  • npm run types:gen regenerates the output
  • npm run types:check (part of npm run checks) fails if the committed output differs from a fresh generation
  • Regeneration runs automatically as part of CI checks

Do not edit files in cms/__generated__/ by hand — they will be overwritten.