-
Notifications
You must be signed in to change notification settings - Fork 680
feat(types): add properties-of<T> type #7359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Firstly, congrats! This is a lot of work and it's not the easiest way to begin in Psalm! Secondly, I have some remarks and checks to add:
|
I found these snippets: https://psalm.dev/r/4971520a7d<?php
class A{
public string $foo;
private int $bar;
}
/**
* @param properties-of<A> $a
* @param private-properties-of<A> $b
*/
function scope($a, string $d){
$b = new A();
$c = $b->$a; //what happens to $c?
$b->$a = 12; //will Psalm detect that type error?
assert(is_string($a)); // will that pass? what will be the type of $a afterwards?
$b->$d = 5; // the private access should be detected
property_exists($b, $a);// this should be flagged as redundant
}
https://psalm.dev/r/9e2eb788b2<?php
class A{
public string $foo;
private int $bar;
private int $bar2;
}
/**
* @param properties-of<A> $a
*/
function scope($a){
$b = match($a) {
'foo' => null,
default => $a
};
if($b === 'bar'){ // this should be allowed
} elseif($b = 'foo') { //this should not because foo was removed
}
}
|
@orklah I'm done for now and this should be ready for review. I reworked this PR but I think the changes are clear if you have a look at the tests. I will initially skip Probably only the lack of template support is currently a bit bad, but from |
@@ -0,0 +1,40 @@ | |||
# Utility types |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where are key-of
and value-of
documented? Maybe they should be added here? Maybe SomeClass::CONST_*
as well? Probably others?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add these as well in another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added key-of
and value-of
, SomeClass::CONST_*
also could need some documentation, but I think it's not a utility type if you look at typescripts definition (https://www.typescriptlang.org/docs/handbook/utility-types.html)
Template/Generic support was easier than I thought! It's done and documented :) |
Seems fine to me :) @ondrejmirtes FYI, this PR introduces a few types in Psalm, namely |
Template Support for |
You linked this PR :) |
@AndrolGenhald do you have some time for review? I'd love to see this in a next alpha of 5.0 🙂 |
Thanks! Sorry, for the delay ;) |
@Patrick-Remy thanks for implementing this feature, but I am having some trouble trying to use it. I have tried many different combinations but I really can't seem to find a way to make it work. P.S. I am trying on Few examples: <?php
class Test
{
/**
* @template T of object
*
* @param T $object
* @param key-of<properties-of<T>> $name
*
* @return void
*/
public static function check(object $object, string $name): void
{
}
}
class Data
{
public string $foo = 'foo!';
public int $bar = 42;
}
$data = new Data();
Test::check($data, 'aa');
<?php
class Test
{
/**
* @template T of object
* @template P of properties-of<T>
*
* @param T $object
* @param key-of<P> $name
*
* @return void
*/
public static function check(object $object, string $name): void
{
}
}
class Data
{
public string $foo = 'foo!';
public int $bar = 42;
}
$data = new Data();
Test::check($data, 'foo');
Test::check($data, 'aa');
Also <?php
class Test
{
/**
* @template T of array
*
* @param T $input
* @param key-of<T> $name
*
* @return void
*/
public static function check(array $input, string $name): void
{
}
}
$data = ['foo' => 'ddd', 'bar' => 42];
Test::check($data, 'foo');
Test::check($data, 'aa'); Tried even providing array shape but no luck.
|
Thanks for your examples, these scenarios aren't currently tested, I'll have a look at these and try to figure out what is going wrong there! |
No worries, as far as I have tried to debug, I think the main issues is that |
@aurimasniekis Did you raised an issue for this specific problem? Pretty sure that it won't get fixed if not raised properly. |
For
ActiveRecord
-patterns in php, there is currently no possibility to type methods likeasArray()
. E.g. for the Yii framework:This PR adds
properties-of<T>
type that currently returns all class property names. There are the variantspublic-properties-of
,protected-properties-of
andprivate-properties-of
.I also fixed an imho bug, that the original class name wasn't proper downpassed in
ReturnTypeAnalyzer
so thatstatic
wasn't properly resolved inTypeExpander
.I aim in a second iteration to return an array-shape form of the class properties, instead of only the names, so that for the above example
properties-of<Foo>
equalsarray{a: int}
instead of currently only'a'
. So thatkey-of<class-properties<Foo>>
will pick all property names. Unfortunately currentlykey-of
only supports constants.TODO
properties-of
properties-of
SKIPPED
T[k]
usable for arrays, e.g.(array{a: string})[a] = string
TLiteralProperty
for further checks likeproperty_exists
Please note, that this is my very first contribution to psalm, so please be aware of any inconveniences. ;)
Partially fixes #3141