Skip to content

[Bug]: Duplicate union types after ClassPropertyProcessor transformation #137

@ragulka

Description

@ragulka

What happened?

While using spatie/laravel-typescript-transformer, I noticed that a property typed as /** @var string[]|Collection<int, string> */ can produce string[] | string[] in the generated TypeScript output (only when the fix in PR #136 is present, though).

This becomes apparent when two conditions are met:

  1. The FixArrayLikeStructuresClassPropertyProcessor is configured to replace array-like classes (as laravel-typescript-transformer does by registering Collection::class and EloquentCollection::class)
  2. The docblock union contains both an explicit array type and an array-like class that resolves to the same array shape after transformation

While the issue manifests when using the Laravel package, the root cause is in the core typescript-transformer package's transformation pipeline, so it should probably be addressed here.

When a property has a PHPDoc union type that includes both an array-like class (e.g. Collection<int, string>) and its equivalent array type (e.g. string[]), the generated TypeScript output contains duplicate union members like string[] | string[].

TypeScriptUnion deduplicates its members in the constructor via the UniqueTypeScriptNodes trait. At construction time, the two members are different node types (TypeScriptGeneric for Collection and TypeScriptArray for string[]), so both are kept.

FixArrayLikeStructuresClassPropertyProcessor then runs and replaces the TypeScriptGeneric(Collection, ...) node with TypeScriptArray([string]) via a Visitor. Now both members are identical, but deduplication has already run and is not triggered again.

A possible fix could be to add a DeduplicateUnionTypesClassPropertyProcessor that runs as the last processor in the chain. It would walk the type tree and re-deduplicate any TypeScriptUnion members after all other processors have finished their transformations.

How to reproduce the bug

Given a class with a property typed as:

/** @var Collection<int, string>|string[] */
public array $items;

When FixArrayLikeStructuresClassPropertyProcessor is configured to replace Collection, the output is:

items: string[] | string[]

Instead of the expected:

items: string[]

Package Version

3.1.1

PHP Version

8.5.4

Which operating systems does with happen with?

macOS

Notes

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions