oi-lab/oi-laravel-ts
A Laravel package that automatically generates TypeScript interfaces from your Eloquent models, with relationship support, custom casts, DataObjects, PHPDoc types, watch mode, and namespace filters for customization.
BREAKING (generated output) — a DTO interface now describes the JSON the DTO produces, not the arguments its constructor accepts. | null is emitted iff the property accepts null, and ? iff the key can genuinely be absent from the payload, which for a DTO means a Spatie\LaravelData\Optional or Lazy marker. A default value no longer makes a property optional, since a serializer emits every declared property.
| PHP declaration | Before | After |
|---|---|---|
public ?string $x = null |
x?: string; |
x: string | null; |
public int $x = 3 |
x?: number; |
x: number; |
public array $x = [] + [@var](https://github.com/var) Foo[] |
x?: IFoo[]; |
x: IFoo[]; |
public string|Optional $x |
x: string; |
x?: string; |
This applies to the interfaces produced from data_namespaces and dataobject_namespaces. Eloquent model interfaces are untouched — ModelInterfaceGenerator already kept the two axes separate. Set data_nullable_style => 'optional' to restore the previous rendering.
data_nullable_style (default 'null'): selects the rendering above, or the legacy 'optional' one where any nullable or defaulted property becomes ? and | null is never emitted.data_aliases: map a DTO's FQCN to a distinct interface base name so two DTOs sharing a short class name can both be generated instead of aborting with DataObjectNameCollisionException. The alias is the name used everywhere, including nested references from other DTOs.included_model_namespaces: the positive counterpart to excluded_namespaces. Adds every Eloquent model of the listed namespaces to the schema as if it lived in app/Models — with its relationships and _count fields — even when nothing in the application points at it through a relationship. Abstract models and non-model classes are skipped, and excluded_namespaces still wins. Also available programmatically via Eloquent::setIncludedModelNamespaces().data_namespaces): emit an I{ClassName} interface for every spatie/laravel-data style DTO found under the configured namespaces. Detection is structural — no dependency on spatie/laravel-data is required. Property names are kept verbatim (camelCase), backed enums become literal unions, nested DTOs become I{Name}, and typed arrays declared via a property [@var](https://github.com/var) Foo[] annotation become IFoo[]. Namespaces are scanned recursively; DTO directories are also watched in --watch mode.data_replaces_model, default false): when enabled, a model mapped to a DTO no longer emits its own Eloquent I{Model} interface. The model is inferred from the DTO's fromModel() factory or set explicitly via data_for_model. Disabled by default, so existing output is unchanged.oi-ts:install-ai-skill and deprecated in favor of the unified php artisan oi:skills command (provided by oi-lab/oi-laravel-development), which discovers and installs skills from all installed oi-lab/* packages.$casts first (skipping class-based casts such as AsUuid), then falls back to getKeyType(). UUID / ULID primary keys declared as string via HasUuids or $keyType are now typed as string instead of number.$fillable.excluded_namespaces): models whose fully-qualified class name begins with one of the listed prefixes are dropped entirely from the schema — including when they are reached through a relationship. Relationship fields pointing to excluded models are also stripped from other interfaces (1.0.17).extended_namespaces): models in these namespaces do not generate standalone interfaces. Instead, for each such model whose short class name matches a base model in the schema, an I{Name}Extended extends I{Name} interface is emitted with the extra fields.Eloquent::setExcludedNamespaces() and Eloquent::setExtendedNamespaces().TypeScriptTypeConverter::convertColumnType() now passes native TypeScript types ([], |, Record<...>) through unchanged, allowing custom_props config entries to declare TypeScript types directly.[@return](https://github.com/return) array<int, int>) now resolve to native TypeScript array types (number[], string[], boolean[]) instead of never.Earlier
1.0.xpatch releases were not recorded here at the time. Seegit logbetweenv1.0.0andv1.0.23for the full history.
Initial release of OI Laravel TypeScript Generator - a comprehensive Laravel package that automatically generates TypeScript interfaces from Eloquent models.
_count fields for relationshipsBuilt with clean architecture principles and separation of concerns:
Eloquent: Facade for model analysis and schema generationModelDiscovery: Discovers all Eloquent models in the applicationTypeExtractor: Extracts type information from model propertiesRelationshipResolver: Detects and extracts relationship metadataCastTypeResolver: Resolves custom Laravel casts to TypeScript typesDataObjectAnalyzer: Analyzes PHP DataObject classesPhpToTypeScriptConverter: Converts PHP types to TypeScriptSchemaBuilder: Orchestrates complete schema buildingConvert: Main orchestrator coordinating TypeScript generationTypeScriptTypeConverter: Handles schema to TypeScript type conversionDataObjectProcessor: Processes PHP DataObjects and generates interfacesModelInterfaceGenerator: Generates TypeScript interfaces for modelsImportManager: Manages TypeScript import statementsJsonLdGenerator: Generates JSON-LD support interfacesphp artisan oi:gen-ts - Generate TypeScript interfacesphp artisan oi:gen-ts --watch - Watch mode for automatic regenerationoutput_path - Custom output path for generated TypeScriptwith_counts - Include relationship count fieldswith_json_ld - Enable JSON-LD supportsave_schema - Save intermediate schema.json for debuggingprops_with_types - Define specific types for propertiescustom_props - Add custom properties to modelsHow can I help you explore Laravel packages today?