Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Permit generics on array shapes #4811

@Firehed

Description

@Firehed

Feature request

My application uses wrapper objects for API responses, based on the endpoint. We implement this using a structure that functions about the same as a Result type. Unfortunately, PHPStan at present doesn't support @template T of array, or similar structures. Ideally I'd like to be able to have a structure like this:

/**
 * @template T of array-shape
 */
class Effect
{
  /** @var ?T */
  private ?array $wrapped;
  /** @var ErrorInterface[] */
  private array $errors = [];

  /**
    * @param T $value
    * @return Effect<T>
    */
  public static function ok(array $value = []): Effect
  {
    $effect = new Effect();
    $effect->wrapped = $value;
    return $effect;
  }
  /**
    * @return Effect<T>
    */
  public static function error(ErrorInterface $error): Effect
  {
    $effect = new Effect();
    $effect->wrapped = null;
    $effect->errors = [$error];
    return $effect;
  }
  // accessors
}

And then have the following code pass:

/** @return Effect<{ foo: string}> */
function execute(): Effect
{
  return Effect::ok(['foo' => 'bar']);
}

/** @return Effect<{ foo: string}> */
function errors(): Effect
{
  $error = new SomeErrorInterface();
  return Effect::error($error);
}

And error:

/** @return Effect<{ foo: string}> */
function execute(): Effect
{
  // Error: returns Effect<{bar: string}>, expected Effect<{foo: string}>
  return Effect::ok(['bar' => 'baz']);
}

It's preferable to be able to inline the shape ({foo: string}), but @template T of array and @return Effect<array{foo: string}> would be perfectly suitable as far as type information goes.

So I suppose this request is a two-parter:

  1. lift the limitation on [phpstan] PHPDoc tag @template T for class {ClassName} with bound type array is not supported.
  2. ideally, but far less important, having an array-shape type for generics that's specifically for non-list array structures (tuples, hashmaps, etc). This would also be covered by supporting inline declaration of type aliases, instead of being limited to the config file.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions