Skip to content

Conditional types by enum not working #11033

@WalterWoshid

Description

@WalterWoshid

Bug report

Example:

/**
 * @phpstan-template T of GotoTarget
 *
 * @phpstan-type CandidateNotesData array{candidate: string, note: string}
 * @phpstan-type PersonalmanagerData array{token: string}
 *
 * @phpstan-type GotoRouteDataTypes array{
 *     'personalmanager': PersonalmanagerData,
 *     'my-pending-reviews': null,
 *     'candidate-notes': CandidateNotesData,
 *     'dashboard': null,
 * }
 *      ↑
 *      Would also be nice if you could use Enums as the key for arrays.
 */
final class GotoRoute
{
    /**
     * @phpstan-var T
     */
    public GotoTarget $target;

    /**
     * @phpstan-var GotoRouteDataTypes[value-of<T>]
     */
    public ?array $data = null;
}

enum GotoTarget: string
{
    case PERSONALMANAGER = 'personalmanager';
    case MY_PENDING_REVIEWS = 'my-pending-reviews';
    case CANDIDATE_NOTES = 'candidate-notes';
    case DASHBOARD = 'dashboard';
}

PhpStan complains for this line: public ?array $data = null; with

phpstan: PHPDoc tag @var for property GotoRoute::$data with type array{personalmanager: array{token: string}, my-pending-reviews: null, candidate-notes: array{candidate: string, note: string}, dashboard: null}[value-of<T>] is not subtype of native type array|null.

and

phpstan: Property GotoRoute::$data type has no value type specified in iterable type array.

What I want to achieve is the following:

  • T ($target) is GotoTarget::DASHBOARD -> $data is null
  • T ($target) is GotoTarget::PERSONALMANAGER -> $data is array{token: string}

It works with this:

/**
 * @phpstan-var (T is GotoTarget::PERSONALMANAGER ? PersonalmanagerData : (T is GotoTarget::CANDIDATE_NOTES ? CandidateNotesData : null))
 */
public ?array $data = null;

But I don't like it, because the more you add, the uglier it gets.

Code snippet that reproduces the problem

https://phpstan.org/r/7fa9183e-5190-4c79-a545-40e40be1033c

Expected output

  • T ($target) is GotoTarget::DASHBOARD -> $data is null
  • T ($target) is GotoTarget::PERSONALMANAGER -> $data is array{token: string}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions