-
-
Notifications
You must be signed in to change notification settings - Fork 565
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
Add generics for Promise. #1170
Conversation
If I have green light - i will proceed with adding all the generics to make psalm/phpstan happy. |
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 generally like this change, please address the comments first and then move on to adapt the rest of the codebase.
I think this is a bit more complicated.
We have a PHPStan stub in our project that looks something like this: /** @template T */
interface Promise
{
/**
* @template TResolved
* @param (callable(T):(Promise<TResolved>|TResolved))|null $onFulfilled
* @param (callable(mixed):mixed)|null $onRejected
* @return Promise<TResolved>
*/
public function then(?callable $onFulfilled = null, ?callable $onRejected = null): Promise;
} It's rather naive, it doesn't account for the return type of But if we do that ( At this point, the game is almost over since PHPStan doesn't support default template types ( But not really. The recently introduced conditional types come to the rescue: /** @template T */
interface Promise
{
/**
* @template TFulfilled of mixed
* @template TRejected of mixed
* @param (callable(T): (Promise<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(mixed): (Promise<TRejected>|TRejected))|null $onRejected
* @return Promise<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : T)
* )>
*/
public function then(?callable $onFulfilled = null, ?callable $onRejected = null): Promise;
} https://phpstan.org/r/722e1db8-c329-4d69-a4fc-aa761ff5b5bf (The code adjusted from phpstan/phpstan-src#1377.) Works nicely for PHPStan but Psalm won't probably understand it. TypeScript's |
There's similar attempt going on here reactphp/promise#188. I think there's still a lot to be done on the SA side before we can do this. |
What is SA? Can we just use the solution proposed by @vhenzl and ignore possible errors for certain edge cases? |
@spawnia I missed the mention of a solution for default types, that was the main blocker IIRC. With conditional types it might work actually. (SA - static analysis) |
@simPod It works: https://phpstan.org/r/722e1db8-c329-4d69-a4fc-aa761ff5b5bf BTW, why two templates |
@vhenzl I don't think the PR there is in working state right now, will have to give it some time. |
One more thing to consider is the variance of the generic type. I believe that /** @template-covariant T */
interface Promise { /* ... */ } Having it invariant ( As I understand it, But I couldn't find any useful authoritative information about promise's variance. The best "proof" online is That our stub I mentioned above actually is covariant, because – well – that's what was needed to make it work. And it makes sense. If we have a field resolver with return type |
Co-authored-by: Benedikt Franke <[email protected]>
Co-authored-by: Benedikt Franke <[email protected]>
# Conflicts: # src/Executor/Promise/Adapter/SyncPromiseAdapter.php
Hi @Warxcell, I checked out the PR and took the liberty of making a few changes. In #1263 I was able to make the breaking change to the interface obsolete. Do you think this PR can be completed without making breaking changes? The failing tests are fixed when reverting the code changes in Without looking into it much deeper, I could not figure out how to resolve the remaining static analysis errors. If there are just a few edge cases, I would be fine with ignoring them - but I would prefer to try and really get the type definitions right so it all checks out. |
# Conflicts: # src/Executor/Promise/Adapter/SyncPromise.php
Will try to, but I have a bit of troubles around some types. Will write here if I need some help :) |
Will close that for now. |
I have typed my props with
but psalm complains about it, because its missing in the Promise.