spatie/laravel-typescript-transformer
Convert PHP classes, enums, and complex types into TypeScript definitions automatically. This Laravel package handles generics, nullable types, and even TypeScript functions, keeping your frontend and backend types in sync.
Architecture fit. This is a build-time code-generation tool, not a runtime dependency. It sits at the PHP↔TypeScript boundary and converts PHP classes, enums, laravel-data DTOs, controller action signatures, and route definitions into .d.ts artifacts. For a TPM this matters because it changes the contract surface between backend and frontend without adding request-path latency, a new service, or a new datastore. Blast radius is concentrated in the build pipeline and the frontend type system, not in production traffic. It fits cleanly into an architecture that already has (a) a Laravel API and (b) an Inertia/Vue/React or standalone TS client, and where DTOs are already expressed as spatie/laravel-data classes. If the API contract is currently hand-written TS interfaces mirrored from PHP, this package is a direct substitute for that manual step.
Integration feasibility. High. It is a Composer package with an artisan install command, a service provider for configuration (v3 moved config out of config/*.php), and an artisan transform command that can be wired into CI. The main prerequisites are PHP 8.2+, Laravel 10+ (v3 hard requirement), and — for the DTO transformer to be useful — spatie/laravel-data. The v3 feature set (controller types, typed route helper with autocompletion, watch mode) is the most compelling part for a product team, because it converts route-name and controller-signature drift into compile-time failures on the frontend rather than runtime 404s. Feasibility is limited mainly by how disciplined the team already is about typed DTOs; if controllers return arrays or JsonResponse with untyped payloads, generation yields little value until those are refactored.
Technical risk. Moderate, concentrated in three areas. First, v3 is young: 3.0.0 was a complete rewrite, and 3.1.0 through 3.3.0 are almost entirely bug fixes to the new surface — broken output paths with GlobalNamespaceWriter, a null-byte crash in the route watcher when filters are configured, install silently failing to register the provider in bootstrap/providers.php under imported class names, route() emitting // for the root route, incorrect generics on paginator aliases, and laravel-data name_mapping_strategy.output being ignored. Each is individually small; collectively they say the v3 edge cases are still being shaken out. Expect a few more minors. Second, ecosystem signal is thin: 400 stars and a reported zero dependents is a weak validation signal compared with core Spatie packages — treat it as "well-maintained by a credible vendor" rather than "battle-tested by the industry". Third, breaking-change cadence: v2→v3 dropped PHP 8.0, dropped Laravel 8/9, moved configuration from a config file to a service provider, and rebuilt on typescript-transformer ^3.0. Any team on v2 faces a real migration, not a composer update. The MIT license is unproblematic; generated .d.ts output is derived from your own source and carries no copyleft exposure.
Key questions.
spatie/laravel-data DTOs, or would this require a DTO normalization project first?Stack fit. Native fit for a Laravel 10/11/12/13 monolith or API with a TypeScript frontend, particularly an Inertia setup where controller types and route helpers map directly onto router.visit(SomeController.update(), …). The v3.2.0 narrowing of method to a literal union ('get' | 'post' | 'put' | 'patch' | 'delete') exists precisely so results are assignable to Inertia without casts — a good sign the maintainers are optimizing for that stack. It is a poor fit for a multi-language or non-Laravel backend, and for teams whose controllers return untyped arrays. For a microservice topology, scope it to the BFF/edge service only; generating types for internal RPC boundaries adds little.
Migration path. Two distinct paths. From manual TS interfaces: additive and low risk — introduce the package, generate types for 2–3 DTOs, and diff the output against the hand-written interfaces to confirm parity before deleting anything. From v2: treat as a scheduled upgrade project. Configuration must be rewritten as a service provider; the dependency moves to typescript-transformer ^3.0; Laravel 8/9 and PHP < 8.2 must already be off the matrix. Do not attempt v2→v3 as an incidental part of a feature branch. Regardless of path, pin explicitly: composer require spatie/laravel-typescript-transformer:^3.3 and review minors deliberately rather than floating.
Compatibility. Strong on the Laravel side (v2.6.0 added Laravel 13; v3 maintains Laravel 10+), and the PHP floor of 8.2 aligns with supported Laravel versions. Frontend-side compatibility is effectively "whatever TypeScript you run", since output is plain .d.ts. The real compatibility constraint is laravel-data version alignment — the 3.1.0 and 3.0.3 fixes show the transformer reaches into DataConfig and MapName/MapOutputName behavior, so a laravel-data major bump should trigger a regen-and-diff check. Secondary integrations (spatie/enum) are optional and degrade gracefully (2.1.5 explicitly stopped failing when spatie/enum is absent).
Sequencing. Five steps, each independently valuable:
laravel-data DTO.typescript:transform to CI plus a staleness check — regenerate and fail if the working tree changes. Add tsc --noEmit on the frontend as the downstream verification.route() helper is the highest-leverage piece and the one most likely to surface latent bugs (renamed routes, duplicate names).Maintenance. Ongoing cost is low but non-zero, and it is scheduled, not reactive: regenerate on every backend change that touches a transformed class, review the resulting diff, and keep the package roughly current. Budget roughly one minor-version review per month and reserve a half-day per minor for regen-and-diff and changelog triage. The heavier maintenance burden is the convention — every engineer touching a DTO or controller must know that the TS contract is derived, not authored. That is a documentation and code-review issue more than a tooling one.
Support. Spatie is a credible, long-lived vendor with published documentation for the transformer and a documented security disclosure channel. This specific repository, however, is small: 400 stars, a reported zero dependents, and a single dominant maintainer. Escalation options are GitHub issues and, at the vendor's discretion, commercial support — there is no SLA unless negotiated. A TPM should record an explicit exit criterion: if the repo goes >9 months without a release or a security-relevant Laravel/TypeScript incompatibility goes unaddressed, fall back to hand-maintained interfaces. Because the output is plain .d.ts, that fallback is cheap — the artifacts can simply be frozen and hand-edited. This is the package's best operational property.
Scaling. Scales well along the axes that matter. Generation cost is linear in the number of transformed classes and runs at build time, so it does not touch request latency, memory, or database load — there is no production scaling concern at all. It scales acceptably in team size (more DTOs, more generated types) up to the point where a single monolithic generated file becomes a merge-conflict magnet; at that point use the namespace writers to split output per domain. The route-helper generator's cost scales with route count and is where a large app (500+ routes) will feel build-time impact first. Watch mode mitigates developer-loop friction but has its own rough edges (the 3.1.0 null-byte crash with route filters is exactly this class of problem).
Failure modes. Ranked by practical impact:
typescript:install reporting success while registering nothing under imported class names. Precedent exists; verify provider registration by inspection rather than trusting exit codes.MapName output). Mitigation: pin to minor, upgrade deliberately, keep the regen diff in the PR.route('home') === '//' bug shows the runtime helper is a live code path, so it needs test coverage of its own.Note that none of these are production runtime failures. On-call impact is effectively nil; the exposure is to the deploy pipeline and to frontend correctness. Frame it that way to stakeholders — this is a developer-experience and correctness investment, not an availability risk.
Ramp-up. For an engineer already fluent in Laravel and TypeScript: roughly one day to productive, one week to fluent with custom transformers and writers. The learning curve is not in the API but in the mental model shift — types are derived from PHP, so the PHP DTO is the source of truth and TS edits are futile. That shift is where teams get burned. Plan a short internal walkthrough, a README note in the frontend repo, and a code-review checklist item ("does this DTO change require a regen?"). Total adoption estimate for a mid-size Laravel/Inertia app: one engineer for two to three weeks end-to-end, with the majority of that time in DTO retrofitting rather than in the package itself.
How can I help you explore Laravel packages today?