Class transformer | typescript-transformer | Spatie

 SPATIE

  TypeScript Transformer
=========================

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Typescript-transformer](https://spatie.be/docs/typescript-transformer/v3)  Transformers  Class transformer

 Version   v3   v2   v1

 Other versions for crawler [v3](https://spatie.be/docs/typescript-transformer/v3) [v2](https://spatie.be/docs/typescript-transformer/v2) [v1](https://spatie.be/docs/typescript-transformer/v1)

  Class transformer
- [ Introduction ](https://spatie.be/docs/typescript-transformer/v3/introduction)
- [ Postcardware ](https://spatie.be/docs/typescript-transformer/v3/postcardware)
- [ Installation ](https://spatie.be/docs/typescript-transformer/v3/installation)
- [ Questions &amp; issues ](https://spatie.be/docs/typescript-transformer/v3/questions-and-issues)
- [ Changelog ](https://spatie.be/docs/typescript-transformer/v3/changelog)
- [ About us ](https://spatie.be/docs/typescript-transformer/v3/about-us)

Getting started
---------------

- [ Setting up ](https://spatie.be/docs/typescript-transformer/v3/getting-started/setting-up)
- [ Running TypeScript Transformer for the first time ](https://spatie.be/docs/typescript-transformer/v3/getting-started/first-run)
- [ Special attributes ](https://spatie.be/docs/typescript-transformer/v3/getting-started/attributes)
- [ Typing properties ](https://spatie.be/docs/typescript-transformer/v3/getting-started/typing-properties)
- [ Replacing common types ](https://spatie.be/docs/typescript-transformer/v3/getting-started/replacing-types)
- [ Formatters ](https://spatie.be/docs/typescript-transformer/v3/getting-started/formatters)

Laravel
-------

- [ Installation and setup ](https://spatie.be/docs/typescript-transformer/v3/laravel/installation-and-setup)
- [ Laravel Data ](https://spatie.be/docs/typescript-transformer/v3/laravel/laravel-data)
- [ Controllers ](https://spatie.be/docs/typescript-transformer/v3/laravel/controllers)
- [ Routes ](https://spatie.be/docs/typescript-transformer/v3/laravel/routes)
- [ Route filters ](https://spatie.be/docs/typescript-transformer/v3/laravel/route-filters)
- [ Watch mode ](https://spatie.be/docs/typescript-transformer/v3/laravel/watch-mode)

Custom transformers
-------------------

- [ Getting started ](https://spatie.be/docs/typescript-transformer/v3/transformers/getting-started)
- [ Class transformer ](https://spatie.be/docs/typescript-transformer/v3/transformers/class-transformer)
- [ Enum transformer ](https://spatie.be/docs/typescript-transformer/v3/transformers/enum-transformer)

Transformed providers
---------------------

- [ Getting started ](https://spatie.be/docs/typescript-transformer/v3/providers/getting-started)
- [ Using different writers in providers ](https://spatie.be/docs/typescript-transformer/v3/providers/writers-in-providers)
- [ Logging in providers ](https://spatie.be/docs/typescript-transformer/v3/providers/logging)
- [ Referencing types ](https://spatie.be/docs/typescript-transformer/v3/providers/references)
- [ Helpers ](https://spatie.be/docs/typescript-transformer/v3/providers/helpers)

TypeScript nodes
----------------

- [ Introduction ](https://spatie.be/docs/typescript-transformer/v3/typescript-nodes/introduction)
- [ Building your own TypeScript node ](https://spatie.be/docs/typescript-transformer/v3/typescript-nodes/custom-nodes)
- [ Visiting TypeScript nodes ](https://spatie.be/docs/typescript-transformer/v3/typescript-nodes/visitor)
- [ Node reference ](https://spatie.be/docs/typescript-transformer/v3/typescript-nodes/reference)

Watch mode
----------

- [ How does it work? ](https://spatie.be/docs/typescript-transformer/v3/watch-mode/how-it-works)
- [ Setting up the runner ](https://spatie.be/docs/typescript-transformer/v3/watch-mode/setting-up-the-runner)
- [ Watch events ](https://spatie.be/docs/typescript-transformer/v3/watch-mode/watch-events)
- [ PHP Nodes ](https://spatie.be/docs/typescript-transformer/v3/watch-mode/php-nodes)

Advanced
--------

- [ Extensions ](https://spatie.be/docs/typescript-transformer/v3/advanced/extensions)
- [ Managing transformers ](https://spatie.be/docs/typescript-transformer/v3/advanced/managing-transformers)
- [ Loggers ](https://spatie.be/docs/typescript-transformer/v3/advanced/loggers)
- [ Custom writers ](https://spatie.be/docs/typescript-transformer/v3/advanced/custom-writers)

 Class transformer
=================

###  On this page

1. [ Choosing properties to transform ](#content-choosing-properties-to-transform)
2. [ Optional properties ](#content-optional-properties)
3. [ Readonly properties ](#content-readonly-properties)
4. [ Hiding properties ](#content-hiding-properties)
5. [ Class property processors ](#content-class-property-processors)
6. [ Fixing array like structures ](#content-fixing-array-like-structures)

Most of the time, transforming a class comes down to taking all the properties and transforming them to a TypeScript object with properties, the package provides an easy-to-extend class for this called `ClassTransformer`.

You can create your own version by extending the `ClassTransformer` and implementing the `shouldTransform` method:

```
use Spatie\TypeScriptTransformer\Transformers\ClassTransformer;

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

In the case above, the transformer will only run when transforming classes which are data objects from the [laravel-data](https://github.com/spatie/laravel-data) package. We encourage you to overwrite certain methods so that the transformer fits your needs.

Choosing properties to transform
--------------------------------------------------------------------------------------------------------------------------------------------------------

By default, all public non-static properties of a class are transformed, but you can overwrite the `properties` method to change this:

```
protected function getProperties(PhpClassNode $phpClassNode): array
{
    return $phpClassNode->getProperties(ReflectionProperty::IS_PUBLIC|ReflectionProperty::IS_PROTECTED);
}
```

Optional properties
-----------------------------------------------------------------------------------------------------------------

It is possible to make a property optional in TypeScript by overwriting the `isPropertyReadonly` method:

```
protected function isPropertyOptional(
    PhpPropertyNode $phpPropertyNode,
    PhpClassNode $phpClassNode,
    TypeScriptNode $type,
    TransformationContext $context,
): bool {
    return str_starts_with($phpPropertyNode->getName(), '_');
}
```

By default, we check whether a property has an `#[Optional]` attribute.

Readonly properties
-----------------------------------------------------------------------------------------------------------------

You can make a property readonly by overwriting the `isPropertyReadonly` method:

```
protected function isPropertyReadonly(
    PhpPropertyNode $phpPropertyNode,
    PhpClassNode $phpClassNode,
    TypeScriptNode $type,
): bool {
   return str_ends_with($phpPropertyNode->getName(), 'Read');
}
```

By default, we check whether a property was made readonly in PHP.

Hiding properties
-----------------------------------------------------------------------------------------------------------

It is possible to completely hide a property from the TypeScript object by overwriting the `isPropertyHidden` method:

```
protected function isPropertyHidden(
    PhpPropertyNode $phpPropertyNode,
    PhpClassNode $phpClassNode,
    TypeScriptProperty $property,
): bool {
    return count($phpPropertyNode->getAttributes(Hidden::class)) > 0;
}
```

By default, we check whether a property has an `#[Hidden]` attribute.

Class property processors
-----------------------------------------------------------------------------------------------------------------------------------

Sometimes a more fine-grained control is needed over how a property is transformed, this is where class property processors come to play. They allow you to update the TypeScript Node of the property, you can create them by implementing the `ClassPropertyProcessor` interface:

```
use Spatie\TypeScriptTransformer\Transformers\ClassPropertyProcessors\ClassPropertyProcessor;

class RemoveNullProcessor implements ClassPropertyProcessor
{
    public function execute(
        PhpPropertyNode $phpPropertyNode,
        ?TypeNode $annotation,
        TypeScriptProperty $property
    ): ?TypeScriptProperty {
        if ($property->type instanceof TypeScriptUnion) {
            $property->type = new TypeScriptUnion(
                array_values(array_filter($property->type->types, fn (TypeScriptNode $type) => !$type instanceof TypeScriptNull))
            );
        }

        return $property;
    }
}
```

You can add these processors to the transformer by overwriting the `classPropertyProcessors` method:

```
protected function classPropertyProcessors(): array
{
    return [
        new RemoveNullProcessor(),
    ];
}
```

A class property processor can also be used to remove properties from the TypeScript object:

```
class RemoveAllStrings implements ClassPropertyProcessor
{
    public function execute(
        PhpPropertyNode $phpPropertyNode,
        ?TypeNode $annotation,
        TypeScriptProperty $property
    ): ?TypeScriptProperty {
        if ($property->type instanceof TypeScriptString) {
            return null;
        }

        return $property;
    }
}
```

Fixing array like structures
--------------------------------------------------------------------------------------------------------------------------------------------

The package ships with `FixArrayLikeStructuresClassPropertyProcessor`, a built-in processor that converts generic array-like types into idiomatic TypeScript:

- `Array` becomes `string[]`
- `Array` becomes `Record`
- `Collection` becomes `User[]` (when registered)

You can register extra classes which behave like arrays as such

```
use Spatie\TypeScriptTransformer\ClassPropertyProcessors\FixArrayLikeStructuresClassPropertyProcessor;

protected function classPropertyProcessors(): array
{
    return [
        new FixArrayLikeStructuresClassPropertyProcessor()
            ->replaceArrayLikeClass(
                Illuminate\Support\Collection::class,
            ),
    ];
}
```

By default, it replaces `Array` generics. This can be disabled by passing `replaceArrays: false` to the constructor.

 A good
match?
-------------

### What we do best

- All things Laravel
- Custom frontend components
- Building APIs
- AI-powered features
- Simplifying things
- Clean solutions
- Integrating services

### Not our cup of tea

- WordPress themes
- Cutting corners
- Free mockups to win a job
- "Just execute the briefing"

 In short: we'd like to be a **substantial part** of your project.

 [ Get in touch via email ](mailto:info@spatie.be?subject=A%20good%20match%21&body=Tell%20us%20as%20much%20as%20you%20can%20about%0A-%20your%20online%20project%0A-%20your%20planning%0A-%20your%20budget%0A-%20%E2%80%A6%0A%0AAnything%20that%20helps%20us%20to%20start%20straightforward%21)
