Support psalm
Add psalm annotations
- [ ] Fix all issues found by psalm
- [x] Increase type specificity
- [x] Add
@psalm-pure - [x] Add
@psalm-assert - [ ] Add proper support for more complex cases like
compose
Type specificity
- [x] Average
- [x] ButLast
- [x] Capture
- [x] CompareObjectHashOn
- [x] CompareOn
- [x] Compose
- [x] Concat
- [x] ConstFunction
- [x] Contains
- [x] Converge
- [ ] Curry
- [ ] CurryN
- [x] Difference
- [x] DropFirst
- [x] DropLast
- [x] Each
- [x] Equal
- [x] ErrorToException
- [x] Every
- [x] Exceptions/InvalidArgumentException
- [x] Exceptions/MatchException
- [x] False
- [x] Falsy
- [x] Filter
- [x] First
- [x] FirstIndexOf
- [x] FlatMap
- [x] Flatten
- [x] Flip
- [x] Functional
- [x] GreaterThan
- [x] GreaterThanOrEqual
- [x] Group
- [x] Head
- [x] Id
- [x] Identical
- [x] IfElse
- [x] IndexesOf
- [x] Intersperse
- [x] Invoke
- [x] InvokeFirst
- [x] InvokeIf
- [x] InvokeLast
- [x] Invoker
- [x] Last
- [x] LastIndexOf
- [x] LessThan
- [x] LessThanOrEqual
- [x] LexicographicCompare
- [x] Map
- [x] Match
- [x] Maximum
- [x] Memoize
- [x] Minimum
- [x] None
- [x] Noop
- [x] Not
- [x] OmitKeys
- [x] PartialAny
- [x] PartialLeft
- [x] PartialMethod
- [x] PartialRight
- [x] Partition
- [x] Pick
- [x] Pluck
- [x] Poll
- [x] Product
- [x] Ratio
- [x] ReduceLeft
- [x] ReduceRight
- [x] Reindex
- [x] Reject
- [x] Repeat
- [x] Retry
- [x] Select
- [x] SelectKeys
- [x] SequenceConstant
- [x] SequenceExponential
- [x] SequenceLinear
- [x] Sequences/ExponentialSequence
- [x] Sequences/LinearSequence
- [x] Some
- [x] Sort
- [x] Sum
- [x] SuppressError
- [x] Tail
- [x] TailRecursion
- [x] TakeLeft
- [x] TakeRight
- [x] Tap
- [x] True
- [x] Truthy
- [x] Unique
- [ ] With
- [ ] Zip
- [ ] ZipAll
Issues
- invoker(), invoke(), partial_method(): no way to annotate method names properly: https://github.com/vimeo/psalm/issues/2500
- Recursive types are not implemented (problem for
compose,curry, etc.): https://github.com/vimeo/psalm/issues/2499
Nice to see that you decided to go with Psalm! I think this is the best choice for a lib like yours, where templates and @psalm- specific annotations can really help end users.
I would like to help with the integration, if you don't mind (and if it's really needed...). Can start from the end of the list, to not mess with you.
@lstrojny, please take a look at #209
@alexeyshockov it would be terrific to collaborate on this topic. I've just pushed my current WIP, would you mind rebasing. Unfortunately it’s going to create a few conflicts, sorry about that. How about we agree to mark an item before working on it, so we avoid duplicate work?
@ondrejmirtes Could @phpstan 0.12 also benefit from this work to make this available to even broader user base?
@jkuchar PHPStan can benefit from generics annotations, not from "pure" or "assert" yet. Instead of assert annotations, right now a TypeSpecifyingExtension has to be written. There are already extensions like that for PHPUnit, for beberlei/assert and webmozart/assert.
Of course, an extension like this can be written to interpret these phpDoc annotations but no one did that yet.
One little thing to add: comment of variable length argument need a fix
It should be mixed ...$arguments. Otherwise, psalm always reports an error.
InvalidArgument - src/test.php:151:56 - Argument 2 of Functional\partial_right expects array<array-key, mixed>, string(BASE) provided
Hi @lstrojny! Since 3.11.3 Psalm supports func_num_args() for conditional types. You could use for compose but with compromises.
/**
* @template A
* @template B
* @template C
* @template D
* @template F
* @template G
* @template H
* @template I
*
* @param callable(A):B $aToB
* @param callable(B):C $bToC
* @param callable(C):D $cToD
* @param callable(D):F $dToF
* @param callable(F):G $fToG
* @param callable(G):H $gToH
* @param callable(H):I $hToI
*
* @return (func_num_args() is 2 ? callable(A):C : (
* func_num_args() is 3 ? callable(A):D : (
* func_num_args() is 4 ? callable(A):F : (
* func_num_args() is 5 ? callable(A):G : (
* func_num_args() is 6 ? callable(A):H : (
* func_num_args() is 7 ? callable(A):I : callable
* ))))))
*/
function compose(
callable $aToB,
callable $bToC,
callable $cToD = null,
callable $dToF = null,
callable $fToG = null,
callable $gToH = null,
callable $hToI = null,
callable ...$others
) {
// impl here
}
In this case you can type limited arguments count. After the limit compose will return just callable.
Unfortunately you can pass null value instead of one of callable.
A similar solution used by rxjs
Inference example:

Error example:

@klimick that’s a great idea, thank you!
Isn't this ready to be merged? (even incomplete) :-)
Hey, for anyone interested in psalm/phpstan support, there is an alternative to this library that has generics: azjezz/psl.
- https://github.com/azjezz/psl/blob/2.1.x/docs/component/vec.md
- https://github.com/azjezz/psl/blob/2.1.x/docs/component/dict.md