-
Notifications
You must be signed in to change notification settings - Fork 659
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
How to allow filter-like functions make restrictions on types? #7944
Comments
I found these snippets: https://psalm.dev/r/9b8357ef92<?php
/**
* @template T
* @param callable(T):bool $filter
* @param iterable<T> $it
* @return iterable<T>
*/
function filterIterable(callable $filter, iterable $it): iterable
{
foreach ($it as $el) {
if ($filter($el)) {
yield $el;
}
}
}
/** @return iterable<int|null> */
function generateIntsOrNulls(): iterable
{
for ($i = 0; ; $i++) {
yield ($i % 2 === 0)
? $i
: null;
}
}
/**
* @param iterable<int> $it
* @return iterable<int>
*/
function takesInts(iterable $it): iterable
{
foreach ($it as $el) {
yield $el * 2;
}
}
$onlyInts = filterIterable('is_int', generateIntsOrNulls());
takesInts($onlyInts);
|
Because Using an extra template actually works for this case, but in general it's been rather buggy to declare a template as a template constraint. For your actual problem, I'm not sure if it's currently possible, I'll have to think about it. Edit: It's definitely not possible right now, I think we'd need to allow templated conditionals in closure types and do something like this, but there might be more difficulties I haven't thought of yet. |
I found these snippets: https://psalm.dev/r/69e63992a6<?php
/**
* @template TFilterParam
* @template T of TFilterParam
* @param callable(TFilterParam):bool $filter
* @param iterable<T> $it
* @return iterable<T>
*/
function filterIterable(callable $filter, iterable $it): iterable
{
foreach ($it as $el) {
if ($filter($el)) {
yield $el;
}
}
}
/** @return iterable<int|null> */
function generateIntsOrNulls(): iterable
{
for ($i = 0; ; $i++) {
yield ($i % 2 === 0)
? $i
: null;
}
}
/**
* @param iterable<int> $it
* @return iterable<int>
*/
function takesInts(iterable $it): iterable
{
foreach ($it as $el) {
yield $el * 2;
}
}
$onlyInts = filterIterable('is_int', generateIntsOrNulls());
takesInts($onlyInts);
|
Consider the following example:
https://psalm.dev/r/9b8357ef92
I'd like to somehow infer that
filterIterable('is_int', generateIntsOrNulls())
returnsiterable<int>
. Of course I cannot do it using the current annotations on the function. Is there a way to type it more precisely so that it infers type restriction from how callable behaves? I guess similar behavior is hard-coded for array_filter function type inference.BTW it's a mystery for me, how did it infer
iterable<mixed, int|mixed|null>
instead ofiterable<mixed, int|null>
The text was updated successfully, but these errors were encountered: