olivermbs / enumshare
A Laravel package to export PHP Enums to TypeScript with labels, metadata, and type-safe frontend access
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/console: ^11.0||^12.0||^13.0
- illuminate/contracts: ^11.0||^12.0||^13.0
- symfony/finder: ^6.0||^7.0||^8.0
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1||^7.10.0
- orchestra/testbench: ^11.0.0||^10.0.0||^9.5.0||^8.22.0
- pestphp/pest: ^2.0||^3.0||^4.0
- pestphp/pest-plugin-arch: ^2.5||^3.0||^4.0
- pestphp/pest-plugin-laravel: ^2.0||^3.0||^4.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1||^2.0
- phpstan/phpstan-phpunit: ^1.3||^2.0
This package is auto-updated.
Last update: 2026-07-29 11:10:49 UTC
README
A Laravel package to export PHP Enums to TypeScript. Simple, type-safe, zero runtime dependencies.
Installation
composer require olivermbs/enumshare
Quick Start
1. Create your enum
<?php namespace App\Enums; use Olivermbs\Enumshare\Attributes\Label; use Olivermbs\Enumshare\Attributes\Meta; enum Status: string { #[Label('Active')] #[Meta(['color' => 'green'])] case Active = 'active'; #[Label('Inactive')] #[Meta(['color' => 'red'])] case Inactive = 'inactive'; }
Any PHP enum can be exported - no trait required.
2. Export
php artisan enums:export
3. Use in TypeScript
import { Status } from '@/Enums/Status'; Status.Active.value // 'active' Status.Active.label // 'Active' Status.Active.meta // { color: 'green' } Status.from('active') // Status.Active entry Status.isValid('active') // true Status.options // [{ value: 'active', label: 'Active' }, ...]
Generated Output
↓ Generates ↓
Output Modes
Configure the output mode in config/enumshare.php:
'mode' => 'full', // or 'minimal'
Full (default)
Includes labels, meta, lookup maps, type guards, and utility methods.
Minimal
Simple output - just values and types (~10 lines per enum):
/* eslint-disable */ // Auto-generated from App\Enums\Status export const Status = { Active: 'active', Inactive: 'inactive', } as const; export type Status = typeof Status[keyof typeof Status];
Configuration
php artisan vendor:publish --tag="enumshare-config"
// config/enumshare.php return [ 'enums' => [ App\Enums\Status::class, ], 'path' => resource_path('js/Enums'), 'mode' => 'full', // 'full' or 'minimal' 'index' => false, // Generate index.ts on every export 'auto_discovery' => true, 'auto_paths' => ['app/Enums'], ];
Commands
php artisan enums:export # Export enums php artisan enums:export --force # Rewrite all, even if unchanged php artisan enums:export --list # List enums that would be exported php artisan enums:export --index # Generate barrel index file php artisan enums:export --prune # Delete stale generated files php artisan enums:export --check # Verify generated files are up to date php artisan enums:export --types # Export TypeScript helper types php artisan enums:export --path=... # Override export path php artisan enums:export --locale=... # Override locale for labels
php artisan about shows an Enumshare section with the active configuration.
CI: Fail on Drift
--check verifies the generated files without writing anything and exits non-zero when
any file is stale or missing — so enum drift becomes a failing build instead of a runtime
surprise:
# .github/workflows/ci.yml - name: Check exported enums are up to date run: php artisan enums:export --check
It also lists orphaned files (generated for enums that no longer exist); clean those up
locally with enums:export --prune, which only ever deletes files carrying the
auto-generated marker.
Attributes
| Attribute | Description |
|---|---|
#[Label('Text')] |
Static label |
#[TranslatedLabel('key')] |
Translation key |
#[Meta(['key' => 'value'])] |
Metadata |
#[ExportMethod] |
Export method result |
#[DontExport] |
Exclude enum from export |
Note: Enums are keyed by short name (class basename). Duplicate names across namespaces will cause a collision error.
Computed properties with #[ExportMethod]
Mark any parameterless public method with #[ExportMethod] and its per-case result is
exported as a typed property on every entry:
↓ Use it in TypeScript ↓
Keeping enums backend-only
Auto-discovery exports every enum in the configured paths. Mark internal enums with
#[DontExport] and they are excluded everywhere — the attribute wins even when the enum
is listed explicitly in the config (you get a warning about the conflict).
Multilingual Labels
Add locales to the config and #[TranslatedLabel] labels are exported for every locale:
'locales' => ['en', 'de'],
Each label becomes an object keyed by locale ({ en: 'Active', de: 'Aktiv' }), and the
generated file includes a resolver — Status.labels('de') returns the German labels,
while each entry keeps the full label object for custom handling.
Auto-Regeneration with Vite
For automatic regeneration during development, install Laravel Wayfinder:
composer require laravel/wayfinder npm install @laravel/vite-plugin-wayfinder
Then configure Vite to watch your enum files:
// vite.config.js import { wayfinder } from '@laravel/vite-plugin-wayfinder'; export default defineConfig({ plugins: [ wayfinder({ command: 'php artisan enums:export --force', patterns: ['app/Enums/**/*.php', 'lang/**/*.php', 'config/enumshare.php'], }), ], });
Note: Wayfinder is optional - only needed for auto-regeneration. You can always run
php artisan enums:exportmanually.
Testing
composer test
License
MIT



