Skip to content

TypeScript

ACMS provides full TypeScript support through automatic type generation. When the dev server runs, it watches your schema and generates TypeScript definitions that give you IDE autocomplete and type checking for all your content fields.

When you run acms dev, the CLI:

  1. Reads acms.json to understand your content structure.
  2. Generates acms.d.ts in your project root with type definitions.
  3. Watches acms.json for changes and regenerates types automatically (with a 300ms debounce).

This means as soon as you register a new field by accessing it in code, the type definitions update and your IDE picks up the new field.

For a schema like:

{
"hero": {
"title": "Welcome",
"subtitle": "Built with ACMS"
},
"contact": {
"email": "hello@example.com"
},
"name": "My Site"
}

ACMS generates the following acms.d.ts:

declare module '@useacms/client' {
export interface ACMSSchema {
hero: {
title: string;
subtitle: string;
};
contact: {
email: string;
};
name: string;
}
export const acms: ACMSSchema;
}

The generated types use TypeScript module augmentation to extend the @useacms/client module. This means when you import acms from the client library, TypeScript knows the exact shape of your content.

import { acms } from '@useacms/client';
// TypeScript knows these fields exist:
acms.hero.title; // string
acms.hero.subtitle; // string
acms.contact.email; // string
acms.name; // string
// TypeScript catches errors:
acms.hero.nonexistent; // Error: Property 'nonexistent' does not exist
acms.missing; // Error: Property 'missing' does not exist

You can regenerate types manually at any time:

Terminal window
acms generate-types
# or the shorthand alias:
acms types

This reads the current acms.json and writes acms.d.ts.

The ACMSSchema interface is the central type that describes your content structure. It’s generated from the content fields in acms.json (excluding _meta).

Nested content paths become nested interfaces:

// acms.hero.title + acms.hero.subtitle + acms.hero.cta.text
export interface ACMSSchema {
hero: {
title: string;
subtitle: string;
cta: {
text: string;
};
};
}

Array fields are typed with their item type:

// acms.features = ["Fast", "Simple", "Flexible"]
export interface ACMSSchema {
features: string[];
}

Fields with boolean or number metadata types are typed accordingly:

export interface ACMSSchema {
settings: {
darkMode: boolean;
maxItems: number;
};
}

The generated acms.d.ts file is picked up automatically by the TypeScript language server in VS Code. You get:

  • Autocomplete — Type acms. and see all available fields.
  • Type checking — Red squiggles for non-existent fields.
  • Hover info — Hover over a field to see its type.
  • Go to definition — Jump to the type definition.

Any editor with TypeScript support (WebStorm, Neovim with LSP, Sublime Text, etc.) picks up the generated types automatically.

Since acms.d.ts is auto-generated, add it to your .gitignore:

.gitignore
acms.d.ts

The file is regenerated on every acms dev start and whenever acms.json changes, so there’s no need to commit it.

If you need to add custom type annotations or extend the generated types, create a separate declaration file:

acms-overrides.d.ts
import '@useacms/client';
declare module '@useacms/client' {
export interface ACMSSchema {
// Add custom fields that might not be auto-detected
settings: {
theme: 'light' | 'dark';
};
}
}

Note that this will merge with the auto-generated types, not replace them.

  • Make sure acms dev is running — it watches for changes and regenerates types.
  • Check that acms.d.ts exists in your project root.
  • Restart your TypeScript language server (in VS Code: Cmd+Shift+P > “TypeScript: Restart TS Server”).
  • Verify acms.d.ts is in the root of your project (or in a path included by tsconfig.json).
  • Make sure your tsconfig.json includes the directory containing acms.d.ts.