spatie/laravel-typescript-transformer
Transform your PHP structures to TypeScript types
3.3.0
8.3M downloads/mo
#899 most downloaded on Packagist
spatie/laravel-typescript-transformer
What this package is like to depend on
Last release 2 months ago
19 Jun 2026
Release timing varies
gaps range from 2 weeks to 9 months
Nearly every release is documented
notes for 29 of 31 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
32 releases · first in 2020
9 releases in the last 12 months
see the full history below
Release timeline
32 releases · Sep 2020 to Jun 2026Releases
latest 32-
3.3.019 Jun 2026Release notes
Open source →A round of fixes for the route generator and the
typescript:installcommand.Fix provider config file detection in install command (#84)
typescript:installfailed for apps created before Laravel 11 that later upgraded, because those apps have nobootstrap/providers.phpfile and the command assumed it was always present. The command now detects the correct provider registration target instead of relying on that file existing.Thanks @TheoGibbons.
Fix silent failure registering the service provider in
typescript:install(#89)typescript:installinjected the service provider intobootstrap/providers.phpwith astr_replaceanchored on a literal fully qualified class string, so it silently did nothing (while still reporting success) whenever that file used short, imported class names (#86). It now uses Laravel'sServiceProvider::addProviderToBootstrapFile(), which evaluates the file rather than matching raw text and therefore handles every layout, and it reports an honest error when registration is not possible.The misleading
typescript:transformmessage now points users totypescript:install, and the unreachable namespace rewriting was dropped to keep the command simple.Thanks @rubenvanassche.
Keep routes that share a controller in the route generator (#90)
Routes were indexed by controller identity (invokable class, or
class@method), so any two routes pointing at the same endpoint overwrote each other and only the last one survived in the generated TypeScript (#87). This silently droppedRoute::inertia()pages and the per-locale routes registered by localized routing packages.RouteController::$actionsis now a flat list of route bindings instead of a map keyed by method, so the resolver appends every route and the helper emits all named routes.Thanks @rubenvanassche.
Throw on missing route in generated
route(), addhasRoutepredicate (#85)Calling the generated
route()with an unknown name returned the literal string/undefined(an accidental result of'/' + undefined), which silently produced broken URLs inhrefattributes and elsewhere.route()now throws when the name is not in the manifest, matching Laravel's server-sideRouteNotFoundExceptionand surfacing the bug at the call site (spatie/typescript-transformer#151).A new exported
hasRoute(name): name is keyof RouteParameterspredicate is emitted alongsideroute(), mirroring Laravel'sRoute::has(). It is the safe way to guard the throw for callers that work with dynamic names, such as locale routing wrappers or runtime-composed strings.// before: could silently produce /undefined const url = route(maybeName); // after if (hasRoute(maybeName)) { const url = route(maybeName); }
For well-typed TypeScript this is impossible to hit, since the parameter type already constrains the name. Dynamic-name callers should guard with
hasRoute()first.Thanks @rubenvanassche.
What's Changed
- Fix provider config file detection in install command by @TheoGibbons in #84
- Throw on missing route in generated
route(), addhasRoutepredicate by @rubenvanassche in #85 - Fix silent failure registering the service provider in typescript:install by @rubenvanassche in #89
- Keep routes that share a controller in the route generator by @rubenvanassche in #90
Full Changelog: 3.2.0...3.3.0
Release notes
Open source →A round of fixes for the route generator and the
typescript:installcommand.Fix provider config file detection in install command (#84)
typescript:installfailed for apps created before Laravel 11 that later upgraded, because those apps have nobootstrap/providers.phpfile and the command assumed it was always present. The command now detects the correct provider registration target instead of relying on that file existing.Thanks @TheoGibbons.
Fix silent failure registering the service provider in
typescript:install(#89)typescript:installinjected the service provider intobootstrap/providers.phpwith astr_replaceanchored on a literal fully qualified class string, so it silently did nothing (while still reporting success) whenever that file used short, imported class names (#86). It now uses Laravel'sServiceProvider::addProviderToBootstrapFile(), which evaluates the file rather than matching raw text and therefore handles every layout, and it reports an honest error when registration is not possible.The misleading
typescript:transformmessage now points users totypescript:install, and the unreachable namespace rewriting was dropped to keep the command simple.Thanks @rubenvanassche.
Keep routes that share a controller in the route generator (#90)
Routes were indexed by controller identity (invokable class, or
class@method), so any two routes pointing at the same endpoint overwrote each other and only the last one survived in the generated TypeScript (#87). This silently droppedRoute::inertia()pages and the per-locale routes registered by localized routing packages.RouteController::$actionsis now a flat list of route bindings instead of a map keyed by method, so the resolver appends every route and the helper emits all named routes.Thanks @rubenvanassche.
Throw on missing route in generated
route(), addhasRoutepredicate (#85)Calling the generated
route()with an unknown name returned the literal string/undefined(an accidental result of'/' + undefined), which silently produced broken URLs inhrefattributes and elsewhere.route()now throws when the name is not in the manifest, matching Laravel's server-sideRouteNotFoundExceptionand surfacing the bug at the call site (spatie/typescript-transformer#151).A new exported
hasRoute(name): name is keyof RouteParameterspredicate is emitted alongsideroute(), mirroring Laravel'sRoute::has(). It is the safe way to guard the throw for callers that work with dynamic names, such as locale routing wrappers or runtime-composed strings.// before: could silently produce /undefined const url = route(maybeName); // after if (hasRoute(maybeName)) { const url = route(maybeName); }For well-typed TypeScript this is impossible to hit, since the parameter type already constrains the name. Dynamic-name callers should guard with
hasRoute()first.Thanks @rubenvanassche.
What's Changed
- Fix provider config file detection in install command by @TheoGibbons in https://github.com/spatie/laravel-typescript-transformer/pull/84
- Throw on missing route in generated
route(), addhasRoutepredicate by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/85 - Fix silent failure registering the service provider in typescript:install by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/89
- Keep routes that share a controller in the route generator by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/90
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/3.2.0...3.3.0
-
3.2.008 May 2026Release notes
Open source →Narrow the controller
methodtype and prioritize HTTP methods (#83)Fixes #76. The generated
RouteDefinitionandMethodRoutetypes previously declaredmethod: string, which forced casts when handing the result to libraries like Inertia that expect'get' | 'post' | 'put' | 'patch' | 'delete'. The output now uses a literal union, so:router.visit(SomeController.update(), { data: { ... } });
just works. On top of that,
LaravelControllerTransformedProvideraccepts a newhttpMethodsPriorityargument that doubles as both filter and sort order. Methods absent from the list are dropped from the output, and the ones that survive are emitted in list order. The default is['get', 'post', 'put', 'patch', 'delete'], so HEAD and OPTIONS (auto-registered by Laravel for every GET route, never invoked by SPAs) are no longer emitted.If you actually relied on the HEAD entries, pass a custom list including
'head'. Thanks @rubenvanassche.Release notes
Open source →Narrow the controller
methodtype and prioritize HTTP methods (#83)Fixes #76. The generated
RouteDefinitionandMethodRoutetypes previously declaredmethod: string, which forced casts when handing the result to libraries like Inertia that expect'get' | 'post' | 'put' | 'patch' | 'delete'. The output now uses a literal union, so:router.visit(SomeController.update(), { data: { ... } });just works. On top of that,
LaravelControllerTransformedProvideraccepts a newhttpMethodsPriorityargument that doubles as both filter and sort order. Methods absent from the list are dropped from the output, and the ones that survive are emitted in list order. The default is['get', 'post', 'put', 'patch', 'delete'], so HEAD and OPTIONS (auto-registered by Laravel for every GET route, never invoked by SPAs) are no longer emitted.If you actually relied on the HEAD entries, pass a custom list including
'head'. Thanks @rubenvanassche. -
3.1.008 May 2026Release notes
Open source →A round of bug fixes for route generation, laravel-data integration, and the writer.
Honor laravel-data
name_mapping_strategy.outputconfig (#81)If your
config/data.phplooked like this:'name_mapping_strategy' => [ 'output' => SnakeCaseMapper::class, ],
The transformer was silently ignoring it and emitting camelCase keys. The processor now resolves property output names through
DataConfig::getDataClass(), so the global mapper, class level, and property levelMapName/MapOutputNameattributes all flow through one source. Thanks @rubenvanassche.Fix
route()helper producing//for the root route (#82)Route::get('/')producedroute('home') === '//'because Laravel's$route->urireturns/for the root and bare paths (without a leading slash) for everything else. The runtime helper then prepended another/. After this fix:route('home'); // '/' (was '//') route('help.index'); // '/help' (unchanged)
Thanks @rubenvanassche.
Fix null byte crash in the route watcher when using filters (#80)
Watching routes with any
RouteFilterconfigured crashed withCommand array element 4 contains a null byte. PHP'sserialize()emits\0*\0markers for protected properties, and Symfony Process rejects command arguments that contain null bytes. Every shipped filter (NamedRouteFilter,ControllerRouteFilter,ClosureRouteFilter) hit this. The serialized payload is now base64 encoded across the process boundary. Thanks @rubenvanassche.Support custom data collections in controller types (#73)
Controller type generation now uses
is_a()instead ofin_array()when checking for data collection classes, so subclasses ofDataCollectionare recognised.buildActionCallExpressionwas also renamed tobuildActionCallNodeto make it overridable. Thanks @iamrgroot.Fix
GlobalNamespaceWriterproducing a broken path when given an absolute path (#79)Passing an absolute path resulted in the output directory being concatenated in front of it:
resources/js/generated/home/user/project/resources/types/generated.d.tsPass a relative filename instead, and the writer will resolve it correctly against the configured output directory. Thanks @A909M.
What's Changed
- Fix null-byte crash in route watcher when using filters by @rubenvanassche in #80
- Honor laravel-data
name_mapping_strategy.outputconfig by @rubenvanassche in #81 - Fix
route()helper producing//for the root route by @rubenvanassche in #82 - Support custom data collections in controller types by @iamrgroot in #73
- Fix
GlobalNamespaceWriterproducing a broken path when given an absolute path by @A909M in #79
Full Changelog: 3.0.3...3.0.4
Release notes
Open source →A round of bug fixes for route generation, laravel-data integration, and the writer.
Honor laravel-data
name_mapping_strategy.outputconfig (#81)If your
config/data.phplooked like this:'name_mapping_strategy' => [ 'output' => SnakeCaseMapper::class, ],The transformer was silently ignoring it and emitting camelCase keys. The processor now resolves property output names through
DataConfig::getDataClass(), so the global mapper, class level, and property levelMapName/MapOutputNameattributes all flow through one source. Thanks @rubenvanassche.Fix
route()helper producing//for the root route (#82)Route::get('/')producedroute('home') === '//'because Laravel's$route->urireturns/for the root and bare paths (without a leading slash) for everything else. The runtime helper then prepended another/. After this fix:route('home'); // '/' (was '//') route('help.index'); // '/help' (unchanged)Thanks @rubenvanassche.
Fix null byte crash in the route watcher when using filters (#80)
Watching routes with any
RouteFilterconfigured crashed withCommand array element 4 contains a null byte. PHP'sserialize()emits\0*\0markers for protected properties, and Symfony Process rejects command arguments that contain null bytes. Every shipped filter (NamedRouteFilter,ControllerRouteFilter,ClosureRouteFilter) hit this. The serialized payload is now base64 encoded across the process boundary. Thanks @rubenvanassche.Support custom data collections in controller types (#73)
Controller type generation now uses
is_a()instead ofin_array()when checking for data collection classes, so subclasses ofDataCollectionare recognised.buildActionCallExpressionwas also renamed tobuildActionCallNodeto make it overridable. Thanks @iamrgroot.Fix
GlobalNamespaceWriterproducing a broken path when given an absolute path (#79)Passing an absolute path resulted in the output directory being concatenated in front of it:
resources/js/generated/home/user/project/resources/types/generated.d.tsPass a relative filename instead, and the writer will resolve it correctly against the configured output directory. Thanks @A909M.
What's Changed
- Fix null-byte crash in route watcher when using filters by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/80
- Honor laravel-data
name_mapping_strategy.outputconfig by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/81 - Fix
route()helper producing//for the root route by @rubenvanassche in https://github.com/spatie/laravel-typescript-transformer/pull/82 - Support custom data collections in controller types by @iamrgroot in https://github.com/spatie/laravel-typescript-transformer/pull/73
- Fix
GlobalNamespaceWriterproducing a broken path when given an absolute path by @A909M in https://github.com/spatie/laravel-typescript-transformer/pull/79
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/3.0.3...3.0.4
-
3.0.317 Mar 2026Release notes
Open source →What's Changed
- Fix method name in TypeScriptTransformerServiceProvider configuration by @dominosaurs in #71
- fix: laravel data MapName attribute output by @bensherred in #70
Full Changelog: 3.0.2...3.0.3
Release notes
Open source →What's Changed
- Fix method name in TypeScriptTransformerServiceProvider configuration by @dominosaurs in https://github.com/spatie/laravel-typescript-transformer/pull/71
- fix: laravel data MapName attribute output by @bensherred in https://github.com/spatie/laravel-typescript-transformer/pull/70
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/3.0.2...3.0.3
-
3.0.216 Mar 2026Release notes
Open source →What's fixed
- Fixed incorrect namespace and non-existent class in
typescript:installcommand stub (#69)Spatie\TypeScriptTransformer\Laravel\TypeScriptTransformerApplicationServiceProvider→Spatie\LaravelTypeScriptTransformer\TypeScriptTransformerApplicationServiceProviderNamespaceWriter→GlobalNamespaceWriter
Release notes
Open source →What's fixed
- Fixed incorrect namespace and non-existent class in
typescript:installcommand stub (#69)Spatie\TypeScriptTransformer\Laravel\TypeScriptTransformerApplicationServiceProvider→Spatie\LaravelTypeScriptTransformer\TypeScriptTransformerApplicationServiceProviderNamespaceWriter→GlobalNamespaceWriter
- Fixed incorrect namespace and non-existent class in
-
3.0.116 Mar 2026Release notes
Open source →What's Changed
- Fix generic arity mismatch in paginator interface type aliases
- Inject Runner via handle() method for testability
- Add tests for TransformTypeScriptCommand
- Update publishable service provider stub path
Release notes
Open source →What's Changed
- Fix generic arity mismatch in paginator interface type aliases
- Inject Runner via handle() method for testability
- Add tests for TransformTypeScriptCommand
- Update publishable service provider stub path
-
3.0.013 Mar 2026Release notes
Open source →This is a major release built on top of the completely rewritten spatie/typescript-transformer v3.
What's New
- Everything new in spatie/typescript-transformer v3
- Service provider configuration - Configure the package in a service provider instead of a config file
- Controller type generation - Automatically generate TypeScript types for your Laravel controller actions, including request parameters and response types
- Route type generation - Generate a typed route helper with full autocompletion for route names and parameters
- Watch mode - File watcher that automatically regenerates TypeScript types as you develop
Breaking Changes
- Requires PHP 8.2+ and Laravel 10+
- Configuration moved from config file to service provider
- Depends on
spatie/typescript-transformer ^3.0
Since it is a complete rewrite, we recommend reading through the new docs and updating your application accodingly.
Release notes
Open source →This is a major release built on top of the completely rewritten spatie/typescript-transformer v3.
What's New
- Everything new in spatie/typescript-transformer v3
- Service provider configuration - Configure the package in a service provider instead of a config file
- Controller type generation - Automatically generate TypeScript types for your Laravel controller actions, including request parameters and response types
- Route type generation - Generate a typed route helper with full autocompletion for route names and parameters
- Watch mode - File watcher that automatically regenerates TypeScript types as you develop
Breaking Changes
- Requires PHP 8.2+ and Laravel 10+
- Configuration moved from config file to service provider
- Depends on
spatie/typescript-transformer ^3.0
Since it is a complete rewrite, we recommend reading through the new docs and updating your application accodingly.
-
3.0.0-beta.116 Jan 2026 pre-releaseRelease notes
Open source →The first beta release of TypeScript Transformer v3, a complete rewrite from scratch!
I don't expect that many things will be changing between beta and release but be cautious.
-
2.6.025 Feb 2026 -
2.5.225 Apr 2025Release notes
Open source →What's Changed
- fix: don't create a compound type when the type is already a TypeScript type by @Bloemendaal in #53
Full Changelog: 2.5.1...2.5.2
Release notes
Open source →What's Changed
- fix: don't create a compound type when the type is already a TypeScript type by @Bloemendaal in https://github.com/spatie/laravel-typescript-transformer/pull/53
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.5.1...2.5.2
-
2.5.114 Feb 2025Release notes
Open source →Allow Laravel 12
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.5.0...2.5.1
-
2.5.004 Oct 2024Release notes
Open source →What's Changed
- Use service container to resolve TypescriptTransformer by @rasmuscnielsen in https://github.com/spatie/laravel-typescript-transformer/pull/47
- feat: support
nullToOptionalby @innocenzi in https://github.com/spatie/laravel-typescript-transformer/pull/46
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.4.1...2.5.0
-
2.4.103 May 2024Release notes
Open source →What's Changed
- Let artisan handle the exceptions by @Tofandel in https://github.com/spatie/laravel-typescript-transformer/pull/41
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.4.0...2.4.1
-
2.4.016 Feb 2024Release notes
Open source →- Laravel 11 support
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.3.2...2.4.0
-
2.3.201 Dec 2023Release notes
Open source →- Use Laravel typescript transformer by default (#34)
- Replace CarbonInterface with a string (#33)
-
2.3.128 Aug 2023 -
2.3.014 Apr 2023 -
2.2.024 Mar 2023 -
2.1.724 Jan 2023Release notes
Open source →What's Changed
- Refactor tests to pest by @AyoobMH in https://github.com/spatie/laravel-typescript-transformer/pull/18
- Add Laravel 10 support by @njoguamos in https://github.com/spatie/laravel-typescript-transformer/pull/20
New Contributors
- @AyoobMH made their first contribution in https://github.com/spatie/laravel-typescript-transformer/pull/18
- @njoguamos made their first contribution in https://github.com/spatie/laravel-typescript-transformer/pull/20
Full Changelog: https://github.com/spatie/laravel-typescript-transformer/compare/2.1.6...2.1.7
-
2.1.618 Nov 2022 -
2.1.522 Aug 2022 -
2.1.422 Aug 2022 -
2.1.325 Jan 2022Nothing published for this version
-
2.1.219 Jan 2022Nothing published for this version
-
2.1.116 Dec 2021 -
2.1.016 Dec 2021Release notes
Open source →- add support for PHP 8.1
- drop support for Laravel 7
- fix issue with union types and Laravel collection transformer
-
2.0.008 Apr 2021Release notes
Open source →- The package is now PHP 8 only
- Added TypeReflectors to reflect method return types, method parameters & class properties within your transformers
- Added support for attributes
- Added support for manually adding TypeScript to a class or property
- Added formatters like Prettier which can format TypeScript code
- Added support for inlining types directly
- Updated the DtoTransformer to be a lot more flexible for your own projects
- Added support for PHP 8 union types
-
1.1.215 Jan 2021 -
1.1.126 Nov 2020 -
1.1.026 Nov 2020 -
1.0.109 Sep 2020 -
1.0.002 Sep 2020