Code Generation
The TypeScript plugin generates code from .as files in two formats: .d.ts for type checking and .js for runtime metadata.
DTS Format
The default format. Generates TypeScript declaration files for static type checking and IDE support.
Given this .as file:
@meta.description 'A product in the catalog'
export interface Product {
@meta.label 'Product Name'
@expect.minLength 3
name: string
@expect.min 0
price: number
inStock: boolean
}The generated .d.ts:
export declare class Product {
name: string
price: number
inStock: boolean
static __is_atscript_annotated_type: true
static type: TAtscriptTypeObject<keyof Product, Product>
static metadata: TMetadataMap<AtscriptMetadata>
static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof Product>
static toJsonSchema: () => any
static toExampleData?: () => any
}
export declare namespace Product {
type DataType = Product
}Key points:
- Interfaces become
declare classwith instance properties and static members - The static members provide access to type metadata, validation, JSON Schema, and example data at runtime
toExampleDatais always optional — whenexampleData: trueis set in plugin options, it's rendered without deprecation; otherwise it's marked@deprecatedProduct.DataTypeis a type alias for the data shape — useful for generic utilities
Interface Extends
When an interface uses extends, the first parent becomes the TypeScript extends target. Properties from additional parents and own properties are rendered in the class body:
interface Base {
id: string
createdAt: string
}
interface Auditable {
updatedBy: string
}
export interface Post extends Base, Auditable {
title: string
}Generates:
export declare class Post extends Base {
updatedBy: string // from Auditable (second parent, inlined)
title: string // own prop
// id and createdAt come via TS extends from Base
static __is_atscript_annotated_type: true
// ... static members
}The JS output resolves all parent properties into a single merged type tree, so runtime metadata includes all inherited props and their annotations.
For types (not interfaces), a companion namespace carries the same static members:
export type Status = 'active' | 'inactive'
declare namespace Status {
type DataType = Status
const __is_atscript_annotated_type: true
const type: TAtscriptTypeComplex<Status>
const metadata: TMetadataMap<AtscriptMetadata>
const validator: (opts?: Partial<TValidatorOptions>) => Validator<TAtscriptAnnotatedType, Status>
const toJsonSchema: () => any
const toExampleData: (() => any) | undefined
}JS Format
Generates JavaScript files with full runtime metadata. Use this when you need validation, metadata access, or serialization.
The same Product .as file generates:
import {
defineAnnotatedType as $,
annotate as $a,
buildJsonSchema as $$, // only with jsonSchema: 'lazy'
createDataFromAnnotatedType as $e, // only with exampleData: true
throwFeatureDisabled as $d, // only with jsonSchema: false (default)
} from '@atscript/typescript/utils'
export class Product {
static __is_atscript_annotated_type = true
static type = {}
static metadata = new Map()
static id = 'Product'
static toJsonSchema() {
return this._jsonSchema ?? (this._jsonSchema = $$(this))
}
static toExampleData() {
return $e(this, { mode: 'example' })
}
}
$('object', Product)
.prop(
'name',
$()
.designType('string')
.tags('string')
.annotate('meta.label', 'Product Name')
.annotate('expect.minLength', 3).$type
)
.prop('price', $().designType('number').tags('number').annotate('expect.min', 0).$type)
.prop('inStock', $().designType('boolean').tags('boolean').$type)
.annotate('meta.description', 'A product in the catalog')The defineAnnotatedType() calls build the type structure and attach all annotations as runtime metadata. Semantic types (like string.email) automatically add validation rules and tags.
Imports depend on config
The example above shows imports for jsonSchema: 'lazy' and exampleData: true. By default:
- JSON Schema is disabled (
jsonSchema: false) —toJsonSchema()callsthrowFeatureDisabled()(aliased as$d) instead, and thebuildJsonSchemaimport is omitted. WithjsonSchema: 'bundle', the schema is pre-computed and embedded as a static return value (no import needed). - Example Data is disabled (
exampleData: false) —toExampleData()is not rendered at all, and thecreateDataFromAnnotatedTypeimport is omitted.
See Configuration for details.
When to Use Which
.d.ts | .js | |
|---|---|---|
| Type checking | Yes | Yes (with .d.ts alongside) |
| IDE IntelliSense | Yes | Yes |
| Runtime validation | Needs .js | Yes |
| Metadata access | Needs .js | Yes |
| JSON Schema | Needs .js | Yes |
| Bundle size | Zero (types only) | Includes runtime metadata |
In practice, use .d.ts during development (generated by VSCode extension on save) and .js for builds that need runtime features.
Next Steps
- CLI — build
.asfiles from the command line - Type Definitions — understand the generated type structure
- Validation — validate data against generated types