0

I cannot figure how to annotate an array returned from API Response. Response have a structure: array{'totalCount': numeric-string, $vehicleType: array} Instead of variable $vehicleType there can be different keys. List of all possible keys ($vehicleType) I have stored in Enum named VehicleType.

Here is an example of API reponse:

{
'totalCount': '2',
'car': [
    {'id': '14', 'brand': 'Ford'},
    {'id': '15', 'brand': 'Honda'}
   ]
}

Instead of 'car' from example I want to declare that it would be a specific string. Preferably I would like to declare all possible variations of that string (from my VehicleType Enum).

PSALM gives me errors, because I cannot declare return array of a method right. Because keys in PHPDoc Array shapes can be only simple strings. More than that - it doesn't support enumeration (with '|') in it. Like 'car'|'airplane'


Example #1 (using Array shapes with 'value-of' in key)

The most obvious and intuitive way - simply does not work. Because of the statement above - keys in PHPDoc Array shapes can be only simple strings

* @return array{'totalCount': numeric-string, value-of<VehicleType>: array}

Example #2 (using Array shapes with generic as key)

* @template ModelKey of value-of<VehicleType>
class ...
....

* @return array{'totalCount': numeric-string, ModelKey: array}
function...

This way PSALM sees ModelKey just as a string 'ModelKey'


Example #3 - Using General arrays I understand that I can declare an multi-element as follows:

@return array<value-of<VehicleType>, array>

This obviously is not a solution:

  1. 'totalCount' element is not declared at all.
  2. This tells PSALM that this array can contain multiple elements with keys from VehicleType enum, instead of only one

Example #4 - Combination of General arrays and Generics Using generics this way:

/** @template TotalElement of array{'totalCount': numeric-string}
 * @template VehicleElement of array<value-of<VehicleType>, array>
 * @template ApiResponseArray of array{TotalElement, VehicleElement}
 */
class 
...
/** @return ApiResponseArray */
public function ...

Makes it even worse - besides problem #2 from previous example we will not have an array with multiple keys, but array with separated arrays


Link: https://phpstan.org/writing-php-code/phpdoc-types I would really like a help with this, not even sure right now if it even possible. Currently my thought about this:

  1. Since I couldn't find on internet how to solve this now I tend to think I will not be able to use generated strings as keys in Array shapes;
  2. I just might have to declare return array as more general. Just using string instead of value-of<VehicleType>;
  3. @return array{'keyOne'|'keyTwo': array}. I will repeat: even this is not working;
  4. Converting Arrays to some Objects and working with them seems like a stupid hack and an overkill
ionov-e
  • 1
  • 1
  • Please write your code as an example on phpstan.org/try, and share the link in PHPStan’s GitHub discussions. The community will definitely help you there! – Ondřej Mirtes Apr 12 '23 at 17:41

0 Answers0