evanschleret/laravel-typebridge

Generate deterministic TypeScript resources from Laravel resource attributes

Maintainers

Package info

github.com/EvanSchleret/laravel-typebridge

pkg:composer/evanschleret/laravel-typebridge

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-18 11:29 UTC

This package is auto-updated.

Last update: 2026-03-18 11:53:23 UTC


README

Laravel TypeBridge banner

Laravel TypeBridge

Deterministic TypeScript generation from Laravel resources.

Packagist Version Packagist Downloads License PHP >= 8.2 Laravel 12.x | 13.x

Why this package

This package helps you keep backend resources and frontend types aligned, with deterministic output and predictable imports.

Requirements

  • PHP >=8.2
  • Laravel 12.x or 13.x
  • Note: Laravel 13.x requires PHP >= 8.3 (Laravel framework requirement)

Installation

composer require --dev evanschleret/laravel-typebridge

Publish the config:

php artisan vendor:publish --provider="EvanSchleret\\LaravelTypeBridge\\TypeBridgeServiceProvider" --tag=typebridge-config

Generated file:

  • config/typebridge.php

Basic usage

Generate files:

php artisan typebridge:generate

Use another output directory:

php artisan typebridge:generate --output-path=resources/typescript

Preview only (no write):

php artisan typebridge:generate --dry-run

Attribute example

Use TypeBridgeResource on Laravel resources (JsonResource or ResourceCollection):

<?php

declare(strict_types=1);

namespace App\Http\Resources;

use App\Models\User;
use EvanSchleret\LaravelTypeBridge\Attributes\TypeBridgeResource;
use Illuminate\Http\Resources\Json\JsonResource;

#[TypeBridgeResource(
    name: 'UserItem',
    structure: [
        'id' => 'number',
        'email' => 'string|null',
        'roles' => '@relation(roles)',
        'manager?' => '@relation(manager)',
    ],
)]
final class UserResource extends JsonResource
{
    public static string $model = User::class;
}

Optional attribute fields:

  • types: local TypeScript aliases/enums declared in the same generated file
  • fileName: per-resource output filename override
  • append: per-resource lines appended at the end of the generated file
  • aliasBase and aliasPlural: alias placeholders used by generation.append_templates

@relation(name) is strict:

  • the resource model must be resolvable
  • the relation method must exist
  • the relation method must return an Eloquent relation

If the relation exists but no generated TypeScript type is available for the related model, the field falls back to any or any[].

Configuration

Published default config

This is the default config generated by vendor:publish:

<?php

declare(strict_types=1);

return [
    'output' => [
        'base_path' => resource_path('typescript'),
    ],
    'sources' => [
        app_path('Http/Resources'),
    ],
    'generation' => [
        'use_semicolons' => false,
        'generate_index' => true,
        'shared_file' => '_api',
        'shared_append' => [],
        'append_templates' => [],
    ],
    'files' => [
        'extension' => 'ts',
        'naming_pattern' => '{name}',
    ],
];

Advanced config example (API wrappers + aliases)

This is an example, not the default:

'generation' => [
    'shared_file' => '_api',
    'shared_append' => [
        'export interface ApiItemResponse<T> {',
        "  status: 'success' | 'error'",
        '  data: T',
        '}',
        'export interface ApiCollectionResponse<T> {',
        '  data: T[]',
        '}',
    ],
    'append_templates' => [
        [
            'name_ends_with' => 'Item',
            'lines' => [
                'export type {base} = ApiItemResponse<{name}>',
                'export type {basePlural} = ApiCollectionResponse<{name}>',
            ],
        ],
    ],
],

With RoleItem, this can generate:

export type Role = ApiItemResponse<RoleItem>
export type Roles = ApiCollectionResponse<RoleItem>

Naming placeholders

For files.naming_pattern:

  • {name}
  • {pascal}
  • {camel}
  • {snake}
  • {kebab}

Example:

'files' => [
    'naming_pattern' => '{kebab}.types',
],

Template placeholders

Inside append_templates.*.lines:

  • {name}: resource name
  • {base}: alias base (aliasBase or suffix stripping)
  • {basePlural}: alias plural (aliasPlural or pluralized base)
  • {pascal}
  • {camel}
  • {snake}
  • {kebab}

Override rules

  • fileName on the attribute overrides files.naming_pattern for one resource
  • --output-path overrides output.base_path

Other packages

If you want to explore more of my Laravel packages:

Open source