Changing types using class property processors | typescript-transformer | Spatie

 SPATIE

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

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Typescript-transformer](https://spatie.be/docs/typescript-transformer/v1)  Dtos  Changing types using class property processors

 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)

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

Usage
-----

- [ General overview ](https://spatie.be/docs/typescript-transformer/v1/usage/general-overview)
- [ Getting started ](https://spatie.be/docs/typescript-transformer/v1/usage/getting-started)
- [ Using transformers ](https://spatie.be/docs/typescript-transformer/v1/usage/using-transformers)
- [ Customizing the output using annotations ](https://spatie.be/docs/typescript-transformer/v1/usage/annotations)
- [ Selecting classes using collectors ](https://spatie.be/docs/typescript-transformer/v1/usage/selecting-classes-using-collectors)

Dto's
-----

- [ Transforming DTOs ](https://spatie.be/docs/typescript-transformer/v1/dtos/transforming-dtos)
- [ Typing properties ](https://spatie.be/docs/typescript-transformer/v1/dtos/typing-properties)
- [ Changing types using class property processors ](https://spatie.be/docs/typescript-transformer/v1/dtos/changing-types-with-class-property-processors)

Laravel
-------

- [ Installation and setup ](https://spatie.be/docs/typescript-transformer/v1/laravel/installation-and-setup)
- [ Executing the transform command ](https://spatie.be/docs/typescript-transformer/v1/laravel/executing-the-transform-command)

      You are viewing the documentation for **an older version** of this package. You can check the version you are using with the following command:

 `                                    composer show spatie/typescript-transformer                                                                                                                                                                                                                                    `

Changing types using class property processors
==============================================

###  On this page

1. [ Default class property processors ](#content-default-class-property-processors)
2. [ Writing class property processors ](#content-writing-class-property-processors)

Class property processors can be used to change the types of class properties for a `DtoTransformer`.

Default class property processors
-----------------------------------------------------------------------------------------------------------------------------------------------------------

In the default package we provide 3 processors:

- `ReplaceDefaultTypesClassPropertyProcessor` replaces some types defined in the configuration, this processor will always run first
- `ApplyNeverClassPropertyProcessor` when a property is typed incorrectly, `never` is used as TypeScript type to indicate a property that should be typed better
- `DtoCollectionClassPropertyProcessor` replaces `DtoCollections` from the `spatie/data-transfer-object` package with their TypeScript equivalent

Specifically for Laravel, we also include the following processors in the Laravel package:

- `LaravelCollectionClassPropertyProcessor` handles Laravel's `Collection` classes like `array`s

Writing class property processors
-----------------------------------------------------------------------------------------------------------------------------------------------------------

A class property processor is any class that implements the `ClassPropertyProcessor` interface:

```
class MyClassPropertyProcessor implements ClassPropertyProcessor
{
    public function process(Type $type, ReflectionProperty $reflection): ?Type
    {
        // Transform the types of the property
    }
}
```

The `process` method has two parameters:

- `Type $type`: a [PHPDocumenter](https://www.phpdoc.org) type that describes the property's type
- `ReflectionProperty $reflection`: the `ReflectionProperty` of the property

You should return a [PHPDocumenter](https://www.phpdoc.org) type or `null` if you want to remove the type from the DTO.

### Returning types

You can return either a PHPDocumenter type or a `TypeScriptType` instance for TypeScript specific types. In a later step of generting the TypeScript definition, each property type will be converted into a `string`.

Using `TypeScriptType`:

```
class MyClassPropertyProcessor implements ClassPropertyProcessor
{
    public function process(Type $type, ReflectionProperty $reflection): ?Type
    {
        return TypeScriptType::create('SomeGenericType');
    }
}
```

Or using a PHPDocumenter type:

```
class MyClassPropertyProcessor implements ClassPropertyProcessor
{
    public function process(Type $type, ReflectionProperty $reflection): ?Type
    {
        return new String_();
    }
}
```

You can find all the possible PHPDocumenter types [here](https://github.com/phpDocumentor/TypeResolver/tree/1.x/src/Types).

### Walking over types

Since any type can exist of arrays, compound types, nullable types, and more, you'll sometimes need to walk (or loop) over these types to specify types case by case. This can be done by including the `ProcessesClassProperties` trait into your ClassPropertyProcessor.

This trait will add a `walk` method that takes an initial type and closure.

Let's say you have a compound type like `string|bool|int`. The `walk` method will run a `string`, `bool` and `int` type through the closure. You can then decide a. type to be returned per type. Finally, the updated compound type will also be passed to the closure. This gives you the opportunity to remove the type by returning `null`.

Let's take a look at an example where we only keep `string` types and remove any others:

```
class MyClassPropertyProcessor implements ClassPropertyProcessor
{
    use ProcessesClassProperties;

    public function process(Type $type, ReflectionProperty $reflection): ?Type
    {
        return $this->walk($type, function (Type $type) {
            if ($type instanceof _String || $type instanceof Compound) {
                return $type;
            }

            return null;
        });
    }
}
```

As you can see, we check in the closure if the type is a `string` or a `compound` type. If it is none of these two types, we remove it by returning `null`.

Why checking for the compound type? In the end, the compound type will be given to the closure. If we removed it, the whole property could be removed from the TypeScript definition.

Do not forget you have to create your own `DtoTransformer` with your class property processors in the `getClassPropertyProcessors` method.
