I found these snippets:
https://psalm.dev/r/d7e2009c63
<?php
class A {
private const KEY_PARTITION = 'process_name';
private const KEY_SORT = 'id';
/**
* @return string[]
*
* @psalm-return array{self::KEY_PARTITION: string, self::KEY_SORT:string}
*/
private function constructKey(string $partitionKey, string $sortKey): array
{
return [
self::KEY_PARTITION => $partitionKey,
self::KEY_SORT => $sortKey,
];
}
}
Psalm output (using commit 6e80887):
ERROR: InvalidReturnStatement - 14:16 - The type 'array{id: string, process_name: string}' does not match the declared return type 'array{A::KEY_PARTITION: string, A::KEY_SORT: string}' for A::constructKey
ERROR: InvalidReturnType - 10:22 - The declared return type 'array{A::KEY_PARTITION: string, A::KEY_SORT: string}' for A::constructKey is incorrect, got 'array{id: string, process_name: string}'
Only string keys work in that context: https://psalm.dev/r/a960775fb7
I found these snippets:
https://psalm.dev/r/a960775fb7
<?php
class A {
private const KEY_PARTITION = 'process_name';
private const KEY_SORT = 'id';
/**
* @return string[]
*
* @psalm-return array{process_name: string, id:string}
*/
private function constructKey(string $partitionKey, string $sortKey): array
{
return [
self::KEY_PARTITION => $partitionKey,
self::KEY_SORT => $sortKey,
];
}
}
Psalm output (using commit 6e80887):
No issues!
Howdy,
we saw that issue being closed without any feedback. Is there any reason why this is closed?
As far as i can see, in list<> class constants are working as array-value. But in array{} they are not working as array-key. Is there any reason why this is not supported?
Test cases: https://psalm.dev/r/e80ed1b65b
I found these snippets:
https://psalm.dev/r/e80ed1b65b
<?php
class Foo {
public const MY_KEY = 'x';
}
/**
* A class constant as list array-value does work and is resolved
*
* @return list<Foo::MY_KEY>
*/
function test__success1(): array {
return [Foo::MY_KEY];
}
/**
* ...even with "wildcard".
*
* @return list<Foo::MY_*>
*/
function test__success2(): array {
return [Foo::MY_KEY];
}
/**
* A class constant as array-key with "optional" works
*
* @return array{Foo::MY_KEY?:string}
*/
function test__success3(): array {
return [Foo::MY_KEY => 'foo'];
}
/**
* ...but an multidimensional array with class constant as array-key required not work.
*
* @return array{Foo::MY_KEY:string}
*/
function test__fails1(): array {
return [Foo::MY_KEY => 'foo'];
}
/**
* Same for wildcard class constant as array-key
*
* @return array{Foo::MY_*:string}
*/
function test__fails2(): array {
return [Foo::MY_KEY => 'foo'];
}
Psalm output (using commit 013467d):
ERROR: InvalidReturnStatement - 37:12 - The inferred type 'array{x: string(foo)}' does not match the declared return type 'array{Foo::MY_KEY: string}' for test__fails1
ERROR: InvalidReturnType - 34:12 - The declared return type 'array{Foo::MY_KEY: string}' for test__fails1 is incorrect, got 'array{x: string(foo)}'
ERROR: InvalidReturnStatement - 45:12 - The inferred type 'array{x: string(foo)}' does not match the declared return type 'array{Foo::MY_*: string}' for test__fails2
ERROR: InvalidReturnType - 42:12 - The declared return type 'array{Foo::MY_*: string}' for test__fails2 is incorrect, got 'array{x: string(foo)}'
I find myself often using constants as array key because that's the only way to have IDE auto-complete and avoid typo. Having to resort to hardcoded strings in annotations completely defeats that purpose.
The point of array{...} annotations is conciseness. If instead Psalm has to worry about all the indirection that class constants provide, a lot of the ergonomics of object-like types disappear from an internal perspective.
I've now made the error more explicit
Most helpful comment
Howdy,
we saw that issue being closed without any feedback. Is there any reason why this is closed?
As far as i can see, in
list<>class constants are working as array-value. But inarray{}they are not working as array-key. Is there any reason why this is not supported?Test cases: https://psalm.dev/r/e80ed1b65b