Skip to content

Commit

Permalink
Add basic template annotations
Browse files Browse the repository at this point in the history
This adds basic type safety annotations for static analyzers like PHPStan and Psalm. This will cover around 80% of the use cases and a follow-up PR for all supported versions will be proposed later to get it to a 100% of close to a 100%.

By adding these annotations methods returning a promise can hint their resolving type by adding `@return PromiseInterface<bool>` when they for example resolve to a boolean. By doing that Psalm and PHPStan will understand that the following bit of code will not become an issue because the method's contract promised a boolean through the promise:

```php
$promise->then(static function (bool $isEnabled) {});
```

However, the following will yield errors:

```php
$promise->then(static function (string $isEnabled) {});
```

This PR is a requirement for reactphp/async#40
  • Loading branch information
WyriHaximus committed Jun 22, 2022
1 parent 77aa876 commit 519e0a0
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 4 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,16 @@ jobs:
- run: composer self-update --2.2 # downgrade Composer for HHVM
- run: hhvm $(which composer) install
- run: hhvm vendor/bin/phpunit

static-analysis:
name: PHPStan
runs-on: ubuntu
continue-on-error: true
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: 8.1
- run: composer require phpstan/phpstan
- name: Execute type checking
run: vendor/bin/phpstan --configuration="phpstan.types.neon.dist"
4 changes: 4 additions & 0 deletions phpstan.types.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parameters:
paths:
- types
level: max
17 changes: 13 additions & 4 deletions src/PromiseInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace React\Promise;

/**
* @template T
* @template R
*/
interface PromiseInterface
{
/**
Expand Down Expand Up @@ -32,10 +36,15 @@ interface PromiseInterface
* than once.
* 3. `$onProgress` (deprecated) may be called multiple times.
*
* @param callable|null $onFulfilled
* @param callable|null $onRejected
* @param callable|null $onProgress This argument is deprecated and should not be used anymore.
* @return PromiseInterface
* @template TFulfilled of mixed
* @template TRejected of mixed
* @param (callable(T): (PromiseInterface<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(R): (PromiseInterface<TRejected>|TRejected))|null $onRejected
* @return PromiseInterface<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : R)
* )>
*/
public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
}
9 changes: 9 additions & 0 deletions types/PromiseInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

use function PHPStan\Testing\assertType;
use function React\Promise\resolve;

$passThroughBoolFn = static fn (bool $bool): bool => $bool;

assertType('React\Promise\PromiseInterface<bool>', resolve(true));
assertType('React\Promise\PromiseInterface<bool>', resolve(true)->then($passThroughBoolFn));

0 comments on commit 519e0a0

Please sign in to comment.