Psalm is an awesome tool for code quality. What I didn't get for a while was how to annotate Doctrine collections. First I used the array syntax, but then I found a better way.

/**
 * @var User[]
 */
private $users;
The first solution
/**
 * @return User[]
 * @psalm-return array<int, User>
 */
public function getUsers(): array
{
  return $this->users->toArray();
}
In the combination with a getter

But then I stumbled over the documentation part of Collection and found out you can use it as an annotation.

/**
 * @var Collection|User[]
 * @psalm-var Collection<int, User>
 */
private $users;
Variable definition
/**
 * @return Collection|User[]
 * @psalm-return Collection<int, User>
 */
public function getUsers(): Collection
{
  return $this->users;
}
Getter

The only missing part for now is the initialization of the variable. When using the following:

public function __construct()
{
  ...
  $this->users = new ArrayCollection();
  ...
}

I will receive a MixedPropertyTypeCoercion error from psalm. My solution for now is to define the error level for it to info. I can't use the Doctrine Collection as it's an interface and I can't use ArrayCollection in the type definition as it won't be an ArrayCollection as soon as the entity is loaded from the database.

If you've got a solution which doesn't require the change of the error level and doesn't need a change on every single instance, let me know.