Skip to content

Commit 8566b8d

Browse files
committed
Add basic template annotations
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
1 parent 77aa876 commit 8566b8d

File tree

5 files changed

+42
-6
lines changed

5 files changed

+42
-6
lines changed

.github/workflows/ci.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@ jobs:
4545
- run: composer self-update --2.2 # downgrade Composer for HHVM
4646
- run: hhvm $(which composer) install
4747
- run: hhvm vendor/bin/phpunit
48+
49+
static-analysis:
50+
name: PHPStan
51+
runs-on: ubuntu-20.04
52+
continue-on-error: true
53+
steps:
54+
- uses: actions/checkout@v3
55+
- uses: shivammathur/setup-php@v2
56+
with:
57+
php-version: 8.1
58+
- run: composer require phpstan/phpstan
59+
- name: Execute type checking
60+
run: vendor/bin/phpstan --configuration="phpstan.types.neon.dist"

phpstan.types.neon.dist

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
parameters:
2+
paths:
3+
- types
4+
level: max

src/PromiseInterface.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
namespace React\Promise;
44

5+
/**
6+
* @template T
7+
* @template R
8+
*/
59
interface PromiseInterface
610
{
711
/**
@@ -32,10 +36,15 @@ interface PromiseInterface
3236
* than once.
3337
* 3. `$onProgress` (deprecated) may be called multiple times.
3438
*
35-
* @param callable|null $onFulfilled
36-
* @param callable|null $onRejected
37-
* @param callable|null $onProgress This argument is deprecated and should not be used anymore.
38-
* @return PromiseInterface
39+
* @template TFulfilled of mixed
40+
* @template TRejected of mixed
41+
* @param (callable(T): (PromiseInterface<TFulfilled>|TFulfilled))|null $onFulfilled
42+
* @param (callable(R): (PromiseInterface<TRejected>|TRejected))|null $onRejected
43+
* @return PromiseInterface<(
44+
* $onFulfilled is not null
45+
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
46+
* : ($onRejected is not null ? TRejected : R)
47+
* )>
3948
*/
4049
public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null);
4150
}

src/functions.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
*
1414
* If `$promiseOrValue` is a promise, it will be returned as is.
1515
*
16-
* @param mixed $promiseOrValue
17-
* @return PromiseInterface
16+
* @template T
17+
* @param T $promiseOrValue
18+
* @return PromiseInterface<T>
1819
*/
1920
function resolve($promiseOrValue = null)
2021
{

types/PromiseInterface.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
use function PHPStan\Testing\assertType;
4+
use function React\Promise\resolve;
5+
6+
$passThroughBoolFn = static fn (bool $bool): bool => $bool;
7+
8+
assertType('React\Promise\PromiseInterface<bool>', resolve(true));
9+
assertType('React\Promise\PromiseInterface<bool>', resolve(true)->then($passThroughBoolFn));

0 commit comments

Comments
 (0)