diff --git a/docs/usage/annotations.md b/docs/usage/annotations.md index 2d555ba1..94d299fc 100644 --- a/docs/usage/annotations.md +++ b/docs/usage/annotations.md @@ -267,6 +267,44 @@ export type FleetData = { } ``` +## Adding additional type information + +Sometimes you need to add additional type information to your TypeScript types, especially when working with specifications like JSON:API. You can use the `LiteralTypeScriptExtraTypes` attribute to add additional properties to your TypeScript types: + +```php +use Spatie\TypeScriptTransformer\Attributes\LiteralTypeScriptExtraTypes; + +#[TypeScript] +#[LiteralTypeScriptExtraTypes([ + 'type' => "'users'", +])] +class UserData { + public string $name; +} +``` + +This will generate the following TypeScript: + +```ts +export type UserData = { + type: 'users'; + name: string; +}; +``` + +You can add as many additional properties as you need: + +```php +#[TypeScript] +#[LiteralTypeScriptExtraTypes([ + 'type' => "'users'", + 'links' => '{self: string}', +])] +class UserData { + public string $name; +} +``` + ## Selecting a transformer Want to define a specific transformer for the file? You can use the following annotation: diff --git a/src/Attributes/LiteralTypeScriptExtraTypes.php b/src/Attributes/LiteralTypeScriptExtraTypes.php new file mode 100644 index 00000000..699a8ea5 --- /dev/null +++ b/src/Attributes/LiteralTypeScriptExtraTypes.php @@ -0,0 +1,21 @@ +extras = $extras; + } + + public function getExtras(): array + { + return $this->extras; + } +} diff --git a/src/Transformers/DtoTransformer.php b/src/Transformers/DtoTransformer.php index a39fbdee..a947ff0d 100644 --- a/src/Transformers/DtoTransformer.php +++ b/src/Transformers/DtoTransformer.php @@ -6,6 +6,7 @@ use ReflectionProperty; use Spatie\TypeScriptTransformer\Attributes\Hidden; use Spatie\TypeScriptTransformer\Attributes\Optional; +use Spatie\TypeScriptTransformer\Attributes\LiteralTypeScriptExtraTypes; use Spatie\TypeScriptTransformer\Structures\MissingSymbolsCollection; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeProcessors\DtoCollectionTypeProcessor; @@ -35,6 +36,7 @@ public function transform(ReflectionClass $class, string $name): ?TransformedTyp $this->transformProperties($class, $missingSymbols), $this->transformMethods($class, $missingSymbols), $this->transformExtra($class, $missingSymbols), + $this->transformLiteralTypeScriptExtraTypes($class, $missingSymbols), ]); return TransformedType::create( @@ -105,6 +107,27 @@ protected function transformExtra( return ''; } + protected function transformLiteralTypeScriptExtraTypes( + ReflectionClass $class, + MissingSymbolsCollection $missingSymbols + ): string { + $attributes = $class->getAttributes(LiteralTypeScriptExtraTypes::class); + + if (empty($attributes)) { + return ''; + } + + $attribute = $attributes[0]->newInstance(); + $extras = $attribute->getExtras(); + + $result = ''; + foreach ($extras as $key => $value) { + $result .= "{$key}: {$value};" . PHP_EOL; + } + + return $result; + } + protected function transformPropertyName( ReflectionProperty $property, MissingSymbolsCollection $missingSymbols diff --git a/tests/Transformers/DtoTransformerTest.php b/tests/Transformers/DtoTransformerTest.php index 5ba756b6..ea052d35 100644 --- a/tests/Transformers/DtoTransformerTest.php +++ b/tests/Transformers/DtoTransformerTest.php @@ -8,6 +8,7 @@ use Spatie\TypeScriptTransformer\Attributes\Hidden; use Spatie\TypeScriptTransformer\Attributes\LiteralTypeScriptType; use Spatie\TypeScriptTransformer\Attributes\Optional; +use Spatie\TypeScriptTransformer\Attributes\LiteralTypeScriptExtraTypes; use Spatie\TypeScriptTransformer\Attributes\TypeScriptType; use Spatie\TypeScriptTransformer\Structures\MissingSymbolsCollection; use Spatie\TypeScriptTransformer\Tests\FakeClasses\Enum\RegularEnum; @@ -161,3 +162,38 @@ class DummyOptionalDto $this->assertMatchesSnapshot($type->transformed); }); + +it('adds extra type information when using LiteralTypeScriptExtraTypes attribute', function () { + #[LiteralTypeScriptExtraTypes([ + 'type' => "'users'", + ])] + class DummyUserData + { + public string $name; + } + + $type = $this->transformer->transform( + new ReflectionClass(DummyUserData::class), + 'Typed' + ); + + assertMatchesSnapshot($type->transformed); +}); + +it('adds multiple extra type information when using LiteralTypeScriptExtraTypes attribute', function () { + #[LiteralTypeScriptExtraTypes([ + 'type' => "'users'", + 'links' => '{self: string}', + ])] + class DummyUserDataWithLinks + { + public string $name; + } + + $type = $this->transformer->transform( + new ReflectionClass(DummyUserDataWithLinks::class), + 'Typed' + ); + + assertMatchesSnapshot($type->transformed); +}); diff --git a/tests/__snapshots__/DtoTransformerTest__it_adds_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt b/tests/__snapshots__/DtoTransformerTest__it_adds_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt new file mode 100644 index 00000000..922d8c16 --- /dev/null +++ b/tests/__snapshots__/DtoTransformerTest__it_adds_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt @@ -0,0 +1,4 @@ +{ +name: string; +type: 'users'; +} \ No newline at end of file diff --git a/tests/__snapshots__/DtoTransformerTest__it_adds_multiple_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt b/tests/__snapshots__/DtoTransformerTest__it_adds_multiple_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt new file mode 100644 index 00000000..b1a05dc3 --- /dev/null +++ b/tests/__snapshots__/DtoTransformerTest__it_adds_multiple_extra_type_information_when_using_LiteralTypeScriptExtraTypes_attribute__1.txt @@ -0,0 +1,5 @@ +{ +name: string; +type: 'users'; +links: {self: string}; +} \ No newline at end of file