Skip to content

feat: add default value support for @template annotations - #832

Merged
romm merged 1 commit into
CuyZ:masterfrom
romm:feat/support-template-default-value
Aug 10, 2026
Merged

feat: add default value support for @template annotations#832
romm merged 1 commit into
CuyZ:masterfrom
romm:feat/support-template-default-value

Conversation

@romm

@romm romm commented Aug 10, 2026

Copy link
Copy Markdown
Member

Every generic of a class had to be given during mapping, even when a sensible fallback existed for some of them. Following PHPStan and Psalm, a template can now declare a default type, making the matching generic optional:

/**
 * @template TValue
 * @template TMeta of array<string, mixed> = array<string, string>
 */
final readonly class SomePage
{
    public function __construct(
        /** @var list<TValue> */
        public array $items,

        /** @var TMeta */
        public array $meta,
    ) {}
}

final readonly class SomeClass
{
    public function __construct(
        // `TMeta` is not filled in, its default type is used
        /** @var SomePage<SomeUser> */
        public SomePage $pageWithDefaultMeta,

        // `TMeta` is filled in, overriding its default type
        /** @var SomePage<SomeUser, array{cursor: int}> */
        public SomePage $pageWithCursorMeta,
    ) {}
}

Templates declaring a default are not counted as required anymore, and the default is used as the fallback for an omitted generic, instead of the template itself.

Fixes #600

Every generic of a class had to be given during mapping, even when a
sensible fallback existed for some of them. Following PHPStan and
Psalm, a template can now declare a default type, making the matching
generic optional:

```php
/**
 * @template TValue
 * @template TMeta of array<string, mixed> = array<string, string>
 */
final readonly class SomePage
{
    public function __construct(
        /** @var list<TValue> */
        public array $items,

        /** @var TMeta */
        public array $meta,
    ) {}
}

final readonly class SomeClass
{
    public function __construct(
        // `TMeta` is not filled in, its default type is used
        /** @var SomePage<SomeUser> */
        public SomePage $pageWithDefaultMeta,

        // `TMeta` is filled in, overriding its default type
        /** @var SomePage<SomeUser, array{cursor: int}> */
        public SomePage $pageWithCursorMeta,
    ) {}
}
```

Templates declaring a default are not counted as required anymore, and
the default is used as the fallback for an omitted generic, instead of
the template itself.
@romm
romm merged commit 0d6efee into CuyZ:master Aug 10, 2026
16 checks passed
@romm
romm deleted the feat/support-template-default-value branch August 10, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for default values for @template

1 participant