[2.x] 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:
$promise->then(static function (bool $isEnabled) {});
However, the following will yield errors:
$promise->then(static function (string $isEnabled) {});
This PR is a requirement for https://github.com/reactphp/async/pull/40
@clue Updated the PR with a types directory for PHPStan type checking, and expanded the annotations a bit
Another thing is that I believe the promise type is covariant on T (and R): https://github.com/webonyx/graphql-php/pull/1170#issuecomment-1155043969
@vhenzl The main goal with this PR is to make it work well enough to make https://github.com/reactphp/async/pull/40 possible and then make the rest fully work in https://github.com/reactphp/promise/pull/223. I'll take a good read of your comment and playgrounds tonight, and do a longer response. But if you have a way to reach the goal I mentioned above then please feel free to suggest it as we realised this is a bigger undertaking than just this PR. And we want to get fibers out in the short term with typing.
I'm not convinced that it's worth trying to type promise with two generic types, nor I'm sure that's actually possible to do it properly. Having a single template type for the fulfilled value like TypeScript has would be much easier: https://github.com/microsoft/TypeScript/blob/2ecde2718722d6643773d43390aa57c3e3199365/lib/lib.es5.d.ts#L1446-L1461
@vhenzl Excellent input and indeed something we've considered before. I agree that having the TFulfilled provides most value here and whether or not TRejected is useful is still debatable, so perhaps we should indeed focus on TFulfilled only for now. Implementing full type safety is indeed somewhat harder than it may seem at first sight, so I'd rather start somewhere and build from there.
After the discussion so far, it's my understanding focusing solely on TFulfilled (as also originally suggested by @WyriHaximus prior to my feedback above) would simplify this PR significantly, probably solve like 90% of use cases and can still serve as a good starting point if we find a need to provide type safe rejection values.
Closing this in favour of #223