Skip to main content

Overview

IlanaORM generates TypeScript types directly from your model files and migration definitions — no build step, no schema file, no manual maintenance. Each model gets:
  • A typed Attributes interface with the correct type per column (including enum union types)
  • A declare class with relation method signatures
  • A barrel index.d.ts for clean imports

Generating Types

npx ilana types
Types are written to a types/ directory by default:
types/
  User.d.ts
  Post.d.ts
  Comment.d.ts
  index.d.ts

Custom output directory

npx ilana types --out=src/types

Auto-generation on migrate

Types are regenerated automatically every time you run a migration:
npx ilana migrate      # runs migration + regenerates types
npx ilana migrate:rollback  # rolls back + regenerates types

Example Output

Given this model and migration:
// models/User.js
export default class User extends Model {
  static table = 'users';
  static softDeletes = true;
  static fillable = ['name', 'email', 'role'];
  static casts = { preferences: 'json' };

  static { this.register(); }

  posts() { return this.hasMany('Post', 'user_id'); }
}
// migrations/create_users_table.js
table.increments('id');
table.string('name').notNullable();
table.string('email').notNullable();
table.enum('role', ['user', 'admin', 'moderator']).defaultTo('user');
table.json('preferences').nullable();
table.timestamps(true, true);
table.timestamp('deleted_at').nullable();
IlanaORM generates:
// types/User.d.ts — auto-generated by `npx ilana types` — do not edit manually
import { Model, HasMany } from 'ilana-orm';
import type { Post } from './index';

export interface UserAttributes {
  id: number;
  name?: string;
  email?: string;
  role?: 'user' | 'admin' | 'moderator';  // ← union type from enum values
  preferences?: Record<string, any> | null;
  created_at?: Date;
  updated_at?: Date;
  deleted_at?: Date | null;
  posts?: Post[];
}

declare class User extends Model<UserAttributes> {
  posts(): HasMany;
}

export default User;
// types/index.d.ts
export { default as User, type UserAttributes } from './User';
export { default as Post, type PostAttributes } from './Post';

Using the Generated Types

import type { UserAttributes } from './types';
import User from './models/User';

// Attributes interface for type-safe objects
const data: UserAttributes = {
  name: 'Alice',
  email: 'alice@example.com',
  role: 'admin', // ✓ — TypeScript validates against 'user' | 'admin' | 'moderator'
};

// Model instance is fully typed
const user = await User.find(1);
user.name;    // string | undefined
user.role;    // 'user' | 'admin' | 'moderator' | undefined
user.posts;   // Post[] | undefined (if eager loaded)

What Gets Inferred

SourceWhat it generates
Migration string, textstring
Migration integer, float, decimalnumber
Migration booleanboolean
Migration date, datetime, timestampDate
Migration json, jsonbRecord<string, any>
Migration enum('col', ['a','b'])'a' | 'b'
static casts = { col: 'json' }Record<string, any>
static casts = { col: 'array' }any[]
static casts = { col: 'boolean' }boolean
.nullable() in migrationType | null
static softDeletes = trueadds deleted_at?: Date | null
Relation methodstyped return (Post[], User | null, etc.)

Notes

  • Types are only generated for TypeScript projects (detected by the presence of tsconfig.json)
  • The types/ directory should be added to .gitignore — regenerate it from migrations instead
  • Do not edit generated files — they will be overwritten on the next migrate or types run
  • For custom cast classes, the column falls back to any — add a manual override if needed