PHP TypeLang Help

@template-covariant

@template-covariant declares a generic type parameter exactly like @template, but with an extra promise attached: the parameter is only ever used in "output" positions — return types — never accepted as an argument. That promise is what lets a static analyzer treat Collection<Dog> as a subtype of Collection<Animal> whenever Dog is a subtype of Animal, a substitution an ordinary invariant @template parameter does not permit, since the analyzer cannot otherwise rule out the parameter being consumed somewhere in a way that substitution would break.

"@template-covariant" <Name> [ "of" <Type> ] [ "=" <Type> ] [ <Description> ]

Parsing a @template-covariant tag produces the same kind of tag as @template, exposing $parameter, $bound, and $default; see @template for what each of those means and how the "of" and "=" clauses work.

final class TemplateCovariantTag extends TypeParameterTag { // Same $parameter/$bound/$default shape as TemplateTag. }

The opposite variance is @template-contravariant, for parameters used only as input.

Both PHPStan and Psalm give @template-covariant dedicated coverage of their own: PHPStan's write-up on template-covariant and Psalm's templated annotations.

05 July 2026