Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Typescript Transformer Laravel Package

spatie/typescript-transformer

Automatically generate TypeScript definitions from your PHP/Laravel code. spatie/typescript-transformer scans classes and types, then outputs .d.ts files so your frontend stays in sync with backend models, DTOs and enums with minimal manual typing.

View on GitHub
Deep Wiki
Context7
3.3.0

A new option to skip manifest generation, a watch mode fix, and expanded route helper docs.

Add withoutManifest() option to skip manifest file generation (#153)

By default the transformer writes a typescript-transformer-manifest.json file to power its caching, only rewriting output files whose contents actually changed. That manifest is unwelcome in some setups: when the output directory is a committed git submodule it surfaces as an unexpected tracked file, and when you want a clean diff or run in CI the caching simply is not needed.

TypeScriptTransformerConfigFactory now exposes a withoutManifest() method that turns off manifest generation entirely. When disabled, WriteFilesAction skips the manifest read and write and writes every file directly.

$config
    ->outputDirectory(resource_path('frontend/types'))
    ->writer(new GlobalNamespaceWriter('generated.d.ts'))
    ->withoutManifest();

Thanks @pawell67.

Fix BetterReflection attribute instantiation in watch mode (#154)

In watch mode attributes are reflected through Roave BetterReflection. PhpAttributeNode::newInstance() constructed each attribute with no arguments before invoking the result, which threw an ArgumentCountError for any attribute with required constructor arguments such as #[LiteralTypeScriptType('string[]')].

The arguments are now spread straight into the constructor, letting PHP bind positional, named, default, and variadic values itself. A regression test covers a constructor-argument attribute reflected through BetterReflection, the path that was previously untested.

Thanks @rubenvanassche.

What's Changed

Full Changelog: https://github.com/spatie/typescript-transformer/compare/3.2.0...3.3.0

3.2.0

A round of bug fixes and a couple of small extensibility improvements, plus broader generic and inherited type support.

Resolve inherited PHPDoc types against the declaring class (#136)

A child class inheriting a [@var](https://github.com/var) annotation from a parent in another namespace would lose the type information. With a parent like:

// namespace App\Models
class ParentModel
{
    /** [@var](https://github.com/var) string[]|SimpleGenericClass<int, string> */
    public array $items;
}

A Child extends ParentModel in App\Models\Children (no use of SimpleGenericClass) used to transform $items as unknown. The transformer now resolves the annotation against the declaring class's namespace, so inherited [@var](https://github.com/var) types keep working across namespaces. Class level [@property](https://github.com/property) and constructor [@param](https://github.com/param) annotations still resolve against the current class, since they belong to that class. Thanks @ragulka.

Make AttributedClassTransformer extensible (#142)

AttributedClassTransformer had TypeScript::class hardcoded in two places, so swapping in a custom attribute meant duplicating the entire transformer. There is now a single attributeClass() hook:

class FrontEndAttributedClassTransformer extends AttributedClassTransformer
{
    protected function attributeClass(): string
    {
        return FrontEnd::class;
    }
}

Thanks @CheshireC4t.

Escape the PHP binary path in the watcher worker (#143)

On macOS via Laravel Herd, PhpExecutableFinder::find() returns /Users/<me>/Library/Application Support/Herd/bin/php84. The space broke Process::fromShellCommandline("$phpBinary $command"):

sh: /Users/<me>/Library/Application: No such file or directory

The watcher then looped on Worker failed to start. Waiting for application to be fixed.... Wrapping the binary in escapeshellarg() fixes it without changing the workerCommand contract. Thanks @mdpoulter.

Recognize [@template-covariant](https://github.com/template-covariant) and [@template-contravariant](https://github.com/template-contravariant) (#144)

getTemplateTagValues() defaults to the [@template](https://github.com/template) name, so generic classes annotated with the variance variants were silently losing their type parameter:

/** [@template-covariant](https://github.com/template-covariant) T */
class Paginated { /* T was dropped */ }

Both variant tag names are now collected alongside [@template](https://github.com/template). Thanks @jakewtaylor.

Re-deduplicate nested nodes after visitor mutations (#149)

When FixArrayLikeStructuresClassPropertyProcessor rewrote a Collection<int, string> next to an existing string[] in a union, the output ended up as string[] | string[]. The constructor time dedup on TypeScriptUnion runs once and cannot catch duplicates introduced by later mutations. A new TypeScriptDeduplicableNode interface (implemented by TypeScriptUnion, TypeScriptIntersection, and TypeScriptArray) is now invoked by the visitor after children are visited, so any Replace or Remove that introduces duplicates is cleaned up automatically:

interface TypeScriptDeduplicableNode
{
    public function deduplicateNodes(): void;
}

Fixes #137. Thanks @rubenvanassche.

Centralize TypeScript literal output and fix escape bugs (#150)

A new OutputsTypeScriptLiteral trait centralizes how scalar values are written as TypeScript literals (string, int, float, bool, null). Strings are now escaped with a hand-rolled map (\, ', \n, \r, \t) and wrapped in single quotes, fixing invalid output for values like App\Models\User or it's. The trait replaces inline interpolation in TypeScriptLiteral, TypeScriptEnum, TypeScriptIdentifier, TypeScriptParameter, and TypeScriptImport, removing four duplicated quoting sites that all had the same hazard. Side effects: TypeScriptLiteral now emits single quoted strings (previously double quoted via json_encode), so the slash escaping problem from json_encode (e.g. image\/png) is gone, and float / null are now accepted by the constructor. Supersedes #138 by @pataar and #148 by @bram-pkg, both of which surfaced facets of the same bug. Thanks @rubenvanassche.

What's Changed

Full Changelog: https://github.com/spatie/typescript-transformer/compare/3.1.1...3.2.0

3.1.1

What's Changed

  • Throw exception when output directory does not exist instead of silently resolving to an empty path (#134)

Previously, when realpath() failed on a non-existent output directory, it would silently return false, which could cause file generation to target the filesystem root (/). The transformer now validates the output directory exists and throws a clear exception if it doesn't.

Full Changelog: https://github.com/spatie/typescript-transformer/compare/3.1.0...3.1.1

3.1.0

What's Changed

  • Support class-level [@template](https://github.com/template) generics in TypeScript output (#133)
  • Remove unused service provider stub

Classes with [@template](https://github.com/template) docblocks now produce generic type aliases:

/**
 * [@template](https://github.com/template) T
 */
class PaginatedResponse
{
    /** [@param](https://github.com/param) array<T> $data */
    public function __construct(
        public int $page = 1,
        public array $data = [],
    ) {}
}

Now correctly generates:

type PaginatedResponse<T> = {
    page: number;
    data: T[];
};

Instead of the previous incorrect output where T was resolved as unknown.

3.0.0

Version 3 is a ground-up rewrite. It introduces a TypeScript AST, a visitor pattern, watch mode, a new extension system, and much more.

TypeScript AST

The package now builds a proper TypeScript Abstract Syntax Tree before writing output. Instead of generating strings directly, transformers create node objects that can be traversed and manipulated before being written to disk:

new TypeScriptAlias('User', new TypeScriptObject([
    new TypeScriptProperty('name', new TypeScriptString()),
    new TypeScriptProperty('age', new TypeScriptNumber()),
]));
// Output: type User = { name: string; age: number }

There are a lot of node types available and you can easily add your own!

Visitor Pattern

A Visitor allows users to traverse the AST, allowing them to replace or completely remove nodes:

Visitor::create()
    ->after(function (TypeScriptUnion $node) {
        if (count($node->types) === 1) {
            return VisitorOperation::replace(array_values($node->types)[0]);
        }
    })
    ->execute($rootNode);

Watch Mode

A file system watcher monitors your PHP files and automatically re-transforms on changes. Your TypeScript definitions stay in sync as you develop - no manual re-running required.

This feature is in beta at the moment.

References & Cross-File Linking

TypeScriptReference nodes connect generated types to the PHP classes they represent. The system automatically resolves references to the correct import paths based on your writer configuration.

TransformedProvider

A new provider interface lets you inject custom transformed types from any source - not just PHP classes:

class AddLaravelCollectionProvider implements TransformedProvider
{
    public function provide(): array
    {
        return [new Transformed(
            typeScriptNode: new TypeScriptAlias(
                new TypeScriptGeneric(new TypeScriptIdentifier('Collection'), [new TypeScriptIdentifier('T')]),
                new TypeScriptGeneric(new TypeScriptIdentifier('Array'), [new TypeScriptIdentifier('T')]),
            ),
            reference: new ClassStringReference(Collection::class),
            location: ['Illuminate', 'Support'],
        )];
    }
}
// Output: type Collection<T> = Array<T>

Rewritten Transformer System

Collectors have been removed. Transformers now decide both whether they can handle a type and how to transform it:

class MyTransformer extends ClassTransformer
{
    protected function shouldTransform(PhpClassNode $phpClassNode): bool
    {
        return $phpClassNode->implementsInterface(Data::class);
    }
}

Rewritten Enum Support

The EnumTransformer now supports union output, native TypeScript enums, and a pluggable EnumProvider interface for custom enum detection.

PHPStan Type Inference

PHPDocumentor has been replaced by PHPStan's type parser. This provides more robust handling of generics, array shapes, key-of, value-of, and complex union/intersection types.

Dual Writer System

ModuleWriter generates TypeScript modules in a directory structure mirroring your PHP namespaces. GlobalNamespaceWriter outputs a single .d.ts declaration file with namespaced types in global scope.

PhpNode Abstraction

Transformers now work with PhpClassNode, PhpPropertyNode, PhpMethodNode instead of raw PHP Reflection objects, providing a unified interface allowing updates to the files to be handled in the same process.

Breaking Changes

  • Requires PHP 8.2+
  • Collectors removed in favor of Transformers
  • DtoTransformer removed - use ClassTransformer with custom property processors
  • TypeProcessors replaced by ClassPropertyProcessor
  • TypeReflectors removed
  • Inline type support removed
  • RecordTypeScriptType and TypeScriptTransformer attributes removed

Since this is a complete rewrite, there isn't an upgrade guide available. We recommend you to first read full documentation and then upgrade your projects accordingly.

3.0.0-beta.1

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.5.0

What's Changed

Full Changelog: https://github.com/spatie/typescript-transformer/compare/2.4.0...2.5.0

2.3.1

What's Changed

Full Changelog: https://github.com/spatie/typescript-transformer/compare/2.3.0...2.3.1

2.3.0

What's Changed

Full Changelog: https://github.com/spatie/typescript-transformer/compare/2.2.2...2.3.0

2.2.1
  • Add support for pseudo types
2.2.0
  • Add support for hidden properties (#54)
2.1.14
  • add support for record types (#51)
2.1.13
  • Add EnumCollector (#42)
  • Ensure transformed types are unique (#44)
2.1.12
  • add support for optional attributes (#30)
  • refactor tests to Pest (#39)
2.1.11
  • fix: Support Collection with array-key key type (#38)
2.1.10
  • Allow non fully qualified names within annotations
2.1.9
  • allow transformation of interfaces (#32)
2.1.8
  • add eslint formatter(#28)
  • let prettier formatter use npx (#29)
2.1.7
  • Allow whitespace in type definitions (#27 )
2.1.6
  • fix the transformation of PHP native enums
2.1.5

What's Changed

New Contributors

Full Changelog: https://github.com/spatie/typescript-transformer/compare/2.1.4...2.1.5

2.1.4
  • allow interfaces in default type replacements
2.1.3
  • add support for transforming to native TypeScript enums
2.1.2
  • fix deprecations
2.1.1
  • add support for PHP 8.1 (#15)
2.1.0
  • Remove classtools dependency
  • Add support for PHP 8.1 enums (#12)
  • Add declare keyword by default to generated output (#13)
2.0.3
  • Fix ProcessTypes to work with Collection types
2.0.2
  • Fix default collector with missing symbols in attributes
2.0.1
  • allow spatie/temporary-directory v2 on dev
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor