psalm
psalm copied to clipboard
Code comment that asserts a variable satisfies a type (@psalm-satisfies)
Feature request: @psalm-satisfies comment annotation
Problem
It can be useful for multiple reasons to annotate the type of a variable that psalm already knows the type of:
- Readability for other developers without them grokking complex return types
- Helping IDEs understand the types of variables (for cases where PHPStorm is not as smart as psalm)
- As a replacement for runtime checks that prevent bugs from code changes elsewhere
Currently this can only be done by using @var
or @psalm-var
comments.
But these tags are unsafe: Psalm treats those as gospel, and assumes whatever you
put in them to be true.
Solution
I propose a new tag that specifies the type of a variable, but that Psalm actually verifies is correct. This would allow expressing type expectations in code.
/**
* @psalm-return ($asList is true ? list<string> : array<string, string>)
*/
function getItems(bool $asList): array
{
$arr = ['a' => 'item', 'another' => 'item'];
return $asList ? array_values($arr) : $arr;
}
$a = getItems(true);
/** @psalm-satisfies list<string> $a */
// From here on out anyone reading can safely assume that $a is list<string>
// And with a bit of luck PhpStorm could start interpreting psalm-satisfies the same as a @var tag
Problems
- For this to be useful for IDEs, they would have to explicitly add support for this tag.
- PHPStorm already has support for a lot of Psalm's annotations, so it might add support if this is implemented.
- An alternative syntax re-using the
@var
annotation could also be considered, see Alternatives below
Alternatives
- It might be more consistent to allow inline
@psalm-assert $variable
instead of introducing a new tag. - To work with IDEs out of the box, the
@var
tag could be re-used:- Perhaps a differentiation between
@var
and@psalm-var
- Or a way to mark a
@var
as an assert:/** @var list<string> $myVar !assert */
- Perhaps a differentiation between
I found these snippets:
https://psalm.dev/r/721c3dae1b
<?php
/**
* @psalm-return ($asList is true ? list<string> : array<string, string>)
*/
function getItems(bool $asList): array
{
$arr = ['a' => 'item', 'another' => 'item'];
return $asList ? array_values($arr) : $arr;
}
$a = getItems(true);
/** @psalm-satisfies list<string> $a */
// From here on out I know that $a is list<string>
// And with a bit of luck PhpStorm could start interpreting psalm-satisfies the same as a @var tag
Psalm output (using commit ef3b018):
ERROR: InvalidDocblock - 14:99 - Unrecognised annotation @psalm-satisfies
INFO: UnusedVariable - 11:1 - $a is never referenced or the value is not used
See https://github.com/vimeo/psalm/pull/10577 for the WIP implementation