Is something wrong with templates in this example: https://psalm.dev/r/113297eeaf?
Why Psalm doesn't agree that Pet<Cat|Dog>
and Cat|Dog
are the same types here?
Can this be solved somehow (besides baseline or suppression)?
<?php
/**
* @template T
*/
abstract class Animal
{
}
/**
* @template T of Cat|Dog
* @extends Animal<T>
*/
abstract class Pet extends Animal
{
abstract public function say(): string;
}
/**
* @extends Pet<Cat>
*/
class Cat extends Pet
{
public function say(): string
{
return 'meow';
}
}
/**
* @extends Pet<Dog>
*/
class Dog extends Pet
{
public function say(): string
{
return 'woof';
}
}
function someFunction(Pet $pet): void
{
echo $pet->say();
}
$pet = rand(0,1) === 0
? new Dog()
: new Cat()
;
someFunction($pet);
ERROR: InvalidArgument - 52:14 - Argument 1 of someFunction expects Pet<Cat|Dog>, but Cat|Dog provided
Using generic typing is not useful in your example.
extends
is sufficient. ACat
is aPet
. ADog
is aPet
.Generic typing is useful to ensure a given function, method, or class returns (and/or accepts) the wanted type.
For example a
PetHouse
can host either aCat
or aDog
, but aPetHouse<Cat>
can only host (and return) aCat
.