wthealth/laravel-enum-transformer

Transforms bensampo/laravel-enum enums to TypeScript with spatie/typescript-transformer v3
86,319 2
Install
composer require wthealth/laravel-enum-transformer
Latest Version:2.0.0
PHP:^8.3
License:MIT
Last Updated:Oct 8, 2026
Links: GitHub  ·  Packagist
Maintainer: badams

Laravel Enum Transformer

CI Action Scrutinizer Code Quality

Adds transformation support for bensampo/laravel-enum based enums to spatie/typescript-transformer v3 and spatie/laravel-typescript-transformer v3.

This package spatie/typescript-transformer PHP Laravel
2.x ^3.0 ^8.3 12, 13
1.x ^2.1.3 ^8.0 8 - 13

Version 2 only supports typescript-transformer v3. v3 changed the Transformer interface, keeping the same name but giving it different method signatures, so one class cannot work with both versions. If you are still on typescript-transformer v2, stay on ^1.1.

Installation

composer require wthealth/laravel-enum-transformer:^2.0 spatie/laravel-typescript-transformer:^3.3

Configuration

typescript-transformer v3 no longer uses config/typescript-transformer.php. You configure it in a service provider that extends TypeScriptTransformerApplicationServiceProvider. Running php artisan typescript:install publishes app/Providers/TypeScriptTransformerServiceProvider.php and registers it in bootstrap/providers.php. You can also write the file yourself. Register LaravelEnumTransformer in it:

<?php

declare(strict_types=1);

namespace App\Providers;

use Spatie\LaravelTypeScriptTransformer\TypeScriptTransformerApplicationServiceProvider as BaseTypeScriptTransformerServiceProvider;
use Spatie\TypeScriptTransformer\TypeScriptTransformerConfigFactory;
use Spatie\TypeScriptTransformer\Writers\FlatModuleWriter;
use Webtools\LaravelEnumTransformer\LaravelEnumTransformer;

class TypeScriptTransformerServiceProvider extends BaseTypeScriptTransformerServiceProvider
{
    protected function configure(TypeScriptTransformerConfigFactory $config): void
    {
        $config
            // `useUnionEnums: false` replaces the old `'transform_to_native_enums' => true`
            ->transformer(new LaravelEnumTransformer(useUnionEnums: false))
            ->transformDirectories(app_path())
            // replaces `'output_file' => resource_path('app/Types/generated.ts')` with the v2 `ModuleWriter`
            ->outputDirectory(resource_path('app/Types'))
            ->writer(new FlatModuleWriter('generated.ts'))
            // stops typescript-transformer-manifest.json being written next to generated.ts (needs typescript-transformer ^3.3)
            ->withoutManifest();
    }
}

If you wrote the provider yourself, register it in bootstrap/providers.php:

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\TypeScriptTransformerServiceProvider::class,
];

Then generate the types as before:

php artisan typescript:transform

Migrating from 1.x / typescript-transformer v2

v2 (config/typescript-transformer.php) v3 (TypeScriptTransformerServiceProvider::configure())
'auto_discover_types' => [app_path()] ->transformDirectories(app_path())
'collectors' => [DefaultCollector::class] removed: each transformer decides what it transforms (see below)
'transformers' => [LaravelEnumTransformer::class] ->transformer(new LaravelEnumTransformer(...))
'transform_to_native_enums' => true new LaravelEnumTransformer(useUnionEnums: false)
'transform_to_native_enums' => false (default) new LaravelEnumTransformer() (or LaravelEnumTransformer::class)
'output_file' => resource_path('app/Types/generated.ts') ->outputDirectory(resource_path('app/Types')) + writer path generated.ts
'writer' => ModuleWriter::class ->writer(new FlatModuleWriter('generated.ts')) (one file, ES module)
'writer' => TypeDefinitionWriter::class ->writer(new GlobalNamespaceWriter('generated.d.ts'))
'default_type_replacements' => [DateTime::class => 'string'] ->replaceType(DateTime::class, 'string')
'formatter' => PrettierFormatter::class ->formatter(PrettierFormatter::class)

After that, delete config/typescript-transformer.php.

Things to be aware of:

  • Use FlatModuleWriter, not ModuleWriter. In v3, ModuleWriter no longer writes a single file. It writes one index.ts per PHP namespace (types/App/Enums/index.ts).
  • Every concrete BenSampo\Enum\Enum subclass in the configured directories is transformed. This matches what Spatie's v3 EnumTransformer does for native enums. The @typescript docblock annotation is no longer needed and is ignored. You can still use the #[TypeScript(name: ..., location: ...)] attribute to rename an enum. Abstract enums are skipped, and #[Spatie\TypeScriptTransformer\Attributes\Hidden] excludes an enum.
  • The command is still php artisan typescript:transform. It also has a new --watch mode, which this transformer supports. In watch mode PHP can't re-load an edited class, so enum constants are read from the source file: overrides of getKeys(), getValue() or getConstants() aren't applied to watch updates, only to full typescript:transform runs.
  • Enums with values TypeScript can't represent are skipped in both union and native mode, instead of generating invalid TypeScript or aborting the transform: anything other than strings and integers (e.g. bool, null, arrays), strings that aren't valid UTF-8, and integers outside JavaScript's safe range (±2^53 - 1).
  • The output directory must exist before the command runs.

Usage

Any enum extending BenSampo\Enum\Enum is transformed:

final class UserType extends Enum
{
    const Administrator = 0;
    const Moderator = 1;
    const Subscriber = 'subscriber';
}

new LaravelEnumTransformer(useUnionEnums: false) turns it into a native TypeScript enum, with the same formatting as 1.x (two space indentation, JSON encoded values):

export enum UserType {
  Administrator = 0,
  Moderator = 1,
  Subscriber = "subscriber",
}

new LaravelEnumTransformer() (the default) turns it into a union of its values:

export type UserType = 0 | 1 | "subscriber";

In 1.x the non-native mode produced an object-like type (export type UserType = { Administrator: 0, ... }). 2.x writes a union of the values instead, which is what Spatie's EnumTransformer does for native PHP enums. An enum with values that are not strings or integers can't be written as a union, so it is skipped in that mode.

Using Spatie's EnumTransformer instead

If you want the same formatting that Spatie's transformer uses for native enums (four space indentation, single quotes), pass BenSampoEnumProvider to it:

use Spatie\TypeScriptTransformer\Transformers\EnumTransformer;
use Webtools\LaravelEnumTransformer\EnumProviders\BenSampoEnumProvider;

$config->transformer(new EnumTransformer(useUnionEnums: false, enumProvider: new BenSampoEnumProvider()));

See the typescript-transformer documentation for more.

Development

composer test      # PHPUnit
composer lint      # Pint (composer format to fix)
composer analyse   # PHPStan / Larastan

License

The MIT License (MIT). Please see License File for more information.

Related Packages

splitstack/laravel-enum-friendly

Make your Laravel enums friendly with TypeScript, selects, and many more conveni...

15,712 1
olivermbs/enumshare

A Laravel package to export PHP Enums to TypeScript with labels, metadata, and t...

3,635 1
wboyz/laravel-enum

Base enum class with some features.

12,437 8
nasyrov/laravel-enums

Laravel package for Enum implementation.

74,569 32
vortgo/dbal-laravel-enum

DBAL package for laravel migrations. Added field type - enum

633 1

Version History

Version Released PHP Laravel License
2.0.0 ^8.3 ^12.0|^13.0 MIT
1.1.1 ^8.0 MIT
1.1.0 ^8.0 MIT
1.0.1 ^8.0 MIT
1.0.0 ^7.4|^8.0 MIT