I want to annotate function, tat takes array with at least key "a" and returns the same array shape with newly added key "x". I tried using type intersection like this:
/**
* @template T of array{a: string}
* @param T $p
* @return T&array{x: int}
*/
function addXToArray(array $p) {
$p['x'] = strlen($p['a']);
return $p;
}
$result = addXToArray(['a' => 'hello']);
This is obviously not the correct way, because PHPstan complains (on level 10 with "Treat PHPDoc types as certain"):
PHPDoc tag @return contains unresolvable type.
I use template T because I need to preserve any other keys that may be present in the argument.
How do I correctly annotate the function?
I use template T because I need to preserve any other keys that may be present in the argument.
That's perhaps the hint needed here.
More specifically, you are using T as an intersection type for @return with something that is not a type: array{} shape.
As has been outlined in phpstan / phpstan Array intersection support #4703 (github.com) the ampersand & of an intersection type does not compute array shapes and likewise it does not the T template in your example.
What you may expect from PHPStan according to ondrejmirtes in February 2024 is as following:
PHPStan WILL NOT add support for "array intersections" but WILL ADD support for "array shapes with extra keys with known type" using this syntax:
array{a: mixed, ...<array-key, mixed>}(same as recently added in Psalm).Please follow this issue to get the updates: #8438 (github.com)