抱歉标题令人困惑,我不确定如何最好地总结问题。
我有一个采用
array-key
类型键的自定义地图类,并且我正在尝试创建一个具有更严格 value-of<BackedEnum>
类型键的实例。
PhpStan 使用枚举值作为键正确检测数组,但在创建自定义地图的实例时,它仅检测字符串。
有没有办法输入地图构造函数以便保留 value-of<Code>
键类型?
游乐场示例:
https://phpstan.org/r/6d38999c-fbfc-4b26-a811-9822c3571e23
<?php declare(strict_types=1);
/**
* @template K of array-key
* @template V
*/
class Map
{
/**
* @var array<K, V>
*/
private array $array;
/**
* @var array<K>
*/
private array $keys;
/**
* @param array<K, V> $a
*/
final public function __construct(array $a = [])
{
$this->array = $a;
$this->keys = \array_keys($a);
}
/**
* @return array<K, V>
*/
public function toArray(): array
{
return $this->array;
}
/**
* @return array<K>
*/
public function getKeys(): array
{
return $this->keys;
}
// ...
}
enum Code: string
{
case FOO = 'foo';
case BAR = 'bar';
}
class Test
{
/**
* This works.
*
* @return array<value-of<Code>, string>
*/
public static function testArray(): array
{
return [
Code::FOO->value => 'foz',
Code::BAR->value => 'baz',
];
}
/**
* This fails as expectd.
*
* @return array<value-of<Code>, string>
*/
public static function testFailingArray(): array
{
return [
Code::FOO->value => 'foz',
Code::BAR->value => 'baz',
'wrong' => 'nogood',
];
}
/**
* FIXME This fails because the type infered from the constructor call is `Map<string, string>`.
*
* @return Map<value-of<Code>, string>
*/
public static function testMap(): Map
{
return new Map([
Code::FOO->value => 'foz',
Code::BAR->value => 'baz',
]);
}
}
直接注释返回值类型。
/** @var Map<value-of<Code>, string> */
return new MapOfCode([
Code::FOO->value => 'foz',
Code::BAR->value => 'baz',
]);
声明更严格的类型,这也保证了输入数组类型的正确性。
/** @extends Map<value-of<Code>, string> */
class MapOfCode extends Map {}
return new MapOfCode([
Code::FOO->value => 'foz',
Code::BAR->value => 'baz',
]);