Skip to content

Commit 6d729c0

Browse files
authored
Extend generic types to specify keys (#219)
1 parent e5d6d11 commit 6d729c0

File tree

3 files changed

+75
-68
lines changed

3 files changed

+75
-68
lines changed

.phpstan.src.neon

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ parameters:
77
- identifier: missingType.iterableValue
88
- "#Binary operation .* between .* and .* results in an error.#"
99
- "#array_flip expects array.*, array given#"
10-
- "#(Function|Method) .* should return .* but returns .*mixed>#"
11-
- "#zip\\(\\) should return .* but returns .*#"
10+
- "#.* should return .* but returns .*#"
11+
- "#Parameter .* of method Pipeline.* expects .*#"
12+
- "#Unable to resolve the template type .* in call to method .*map\\(\\)#"

src/Standard.php

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@
5353
/**
5454
* Concrete pipeline with sensible default callbacks.
5555
*
56-
* @template TOutput
57-
* @template-implements IteratorAggregate<array-key, TOutput>
56+
* @template TKey
57+
* @template TValue
58+
* @template-implements IteratorAggregate<TKey, TValue>
5859
*/
5960
class Standard implements IteratorAggregate, Countable
6061
{
@@ -68,7 +69,7 @@ class Standard implements IteratorAggregate, Countable
6869
/**
6970
* Constructor with an optional source of data.
7071
*
71-
* @param null|iterable<TOutput> $input
72+
* @param null|iterable<TKey, TValue> $input
7273
*/
7374
public function __construct(?iterable $input = null)
7475
{
@@ -120,10 +121,10 @@ private function discard(): void
120121
/**
121122
* Appends the contents of an iterable to the end of the pipeline.
122123
*
123-
* @param null|iterable<TOutput> $values
124+
* @param null|iterable<TKey, TValue> $values
124125
*
125-
* @phpstan-self-out self<TOutput>
126-
* @return Standard<TOutput>
126+
* @phpstan-self-out self<TKey, TValue>
127+
* @return Standard<TKey, TValue>
127128
*/
128129
public function append(?iterable $values = null): self
129130
{
@@ -138,23 +139,24 @@ public function append(?iterable $values = null): self
138139
/**
139140
* Appends a list of values to the end of the pipeline.
140141
*
141-
* @param TOutput ...$vector
142+
* @param TValue ...$vector
142143
*
143-
* @phpstan-self-out self<TOutput>
144-
* @return Standard<TOutput>
144+
* @phpstan-self-out self<TKey, TValue>
145+
* @return Standard<TKey, TValue>
145146
*/
146147
public function push(...$vector): self
147148
{
149+
/** @var iterable<array-key, TValue> $vector */
148150
return $this->append($vector);
149151
}
150152

151153
/**
152154
* Prepends the pipeline with the contents of an iterable.
153155
*
154-
* @param null|iterable<TOutput> $values
156+
* @param null|iterable<TKey, TValue> $values
155157
*
156-
* @phpstan-self-out self<TOutput>
157-
* @return Standard<TOutput>
158+
* @phpstan-self-out self<TKey, TValue>
159+
* @return Standard<TKey, TValue>
158160
*/
159161
public function prepend(?iterable $values = null): self
160162
{
@@ -169,10 +171,10 @@ public function prepend(?iterable $values = null): self
169171
/**
170172
* Prepends the pipeline with a list of values.
171173
*
172-
* @param TOutput ...$vector
174+
* @param TValue ...$vector
173175
*
174-
* @phpstan-self-out self<TOutput>
175-
* @return Standard<TOutput>
176+
* @phpstan-self-out self<TKey, TValue>
177+
* @return Standard<TKey, TValue>
176178
*/
177179
public function unshift(...$vector): self
178180
{
@@ -209,7 +211,7 @@ private function willReplace(?iterable $values = null): bool
209211
*
210212
* Utility method for appending/prepending methods.
211213
*
212-
* @return Standard<TOutput>
214+
* @return Standard<TKey, TValue>
213215
*/
214216
private function join(iterable $left, iterable $right): self
215217
{
@@ -237,8 +239,8 @@ private static function joinYield(iterable $left, iterable $right): Generator
237239

238240
/**
239241
* Flattens inputs: arrays become lists.
240-
* @phpstan-self-out self<mixed>
241-
* @return Standard<mixed>
242+
* @phpstan-self-out self<array-key, mixed>
243+
* @return Standard<array-key, mixed>
242244
*/
243245
public function flatten(): self
244246
{
@@ -250,12 +252,13 @@ public function flatten(): self
250252
/**
251253
* An extra variant of `map` which unpacks arrays into arguments. Flattens inputs if no callback provided.
252254
*
255+
* @template TUnpackKey
253256
* @template TUnpack
254257
*
255-
* @param null|callable(mixed...): (TUnpack|Generator<array-key, TUnpack, mixed, mixed>) $func A callback that accepts any number of arguments and returns a single value.
258+
* @param null|callable(mixed...): (TUnpack|Generator<TUnpackKey, TUnpack, mixed, mixed>) $func A callback that accepts any number of arguments and returns a single value.
256259
*
257-
* @phpstan-self-out self<TUnpack>
258-
* @return Standard<TUnpack>
260+
* @phpstan-self-out self<TUnpackKey, TUnpack>
261+
* @return Standard<TUnpackKey, TUnpack>
259262
*/
260263
public function unpack(?callable $func = null): self
261264
{
@@ -277,8 +280,8 @@ static function (iterable $args = []) use ($func) {
277280
* @param int<1, max> $length The size of each chunk.
278281
* @param bool $preserve_keys When set to true keys will be preserved. Default is false which will reindex the chunk numerically.
279282
*
280-
* @phpstan-self-out self<list<TOutput>>
281-
* @return Standard<list<TOutput>>
283+
* @phpstan-self-out self<array-key, array<TKey, TValue>>
284+
* @return Standard<array-key, array<TKey, TValue>>
282285
*/
283286
public function chunk(int $length, bool $preserve_keys = false): self
284287
{
@@ -319,12 +322,13 @@ private static function toChunks(Generator $input, int $length, bool $preserve_k
319322
*
320323
* With no callback is a no-op (can safely take a null).
321324
*
325+
* @template TMapKey
322326
* @template TMapValue
323327
*
324-
* @param null|(callable(): (TMapValue|Generator<array-key, TMapValue, mixed, mixed>))|(callable(TOutput): (TMapValue|Generator<array-key, TMapValue, mixed, mixed>)) $func A callback must either return a value or yield values (return a generator).
328+
* @param null|(callable(): (TMapValue|Generator<TMapKey, TMapValue, mixed, mixed>))|(callable(TValue): (TMapValue|Generator<TMapKey, TMapValue, mixed, mixed>)) $func A callback must either return a value or yield values (return a generator).
325329
*
326-
* @phpstan-self-out self<TMapValue>
327-
* @return Standard<TMapValue>
330+
* @phpstan-self-out self<TMapKey, TMapValue>
331+
* @return Standard<TMapKey, TMapValue>
328332
*/
329333
public function map(?callable $func = null): self
330334
{
@@ -387,10 +391,10 @@ private static function apply(iterable $previous, callable $func): Generator
387391
*
388392
* @template TCast
389393
*
390-
* @param null|(callable(TOutput): TCast)|(callable(): TCast) $func A callback must return a value.
394+
* @param null|(callable(TValue): TCast)|(callable(): TCast) $func A callback must return a value.
391395
*
392-
* @phpstan-self-out self<TCast>
393-
* @return Standard<TCast>
396+
* @phpstan-self-out self<TKey, TCast>
397+
* @return Standard<TKey, TCast>
394398
*/
395399
public function cast(?callable $func = null): self
396400
{
@@ -433,11 +437,11 @@ private static function applyOnce(iterable $previous, callable $func): Generator
433437
*
434438
* With no callback drops all null and false values (not unlike array_filter does by default).
435439
*
436-
* @param null|callable(TOutput): bool $func A callback that accepts a single value and returns a boolean value.
440+
* @param null|callable(TValue): bool $func A callback that accepts a single value and returns a boolean value.
437441
* @param bool $strict When true, only `null` and `false` are filtered out.
438442
*
439-
* @phpstan-self-out self<TOutput>
440-
* @return Standard<TOutput>
443+
* @phpstan-self-out self<TKey, TValue>
444+
* @return Standard<TKey, TValue>
441445
*/
442446
public function filter(?callable $func = null, bool $strict = false): self
443447
{
@@ -509,10 +513,10 @@ private static function resolveStringPredicate(callable $func): callable
509513
/**
510514
* Skips elements while the predicate returns true, and keeps everything after the predicate returns false just once.
511515
*
512-
* @param callable(TOutput): bool $predicate A callback returning boolean value.
516+
* @param callable(TValue): bool $predicate A callback returning boolean value.
513517
*
514-
* @phpstan-self-out self<TOutput>
515-
* @return Standard<TOutput>
518+
* @phpstan-self-out self<TKey, TValue>
519+
* @return Standard<TKey, TValue>
516520
*/
517521
public function skipWhile(callable $predicate): self
518522
{
@@ -610,7 +614,7 @@ public function getIterator(): Traversable
610614

611615
/**
612616
* By default, returns all values regardless of keys used, discarding all keys in the process. This is a terminal operation.
613-
* @return list<TOutput>
617+
* @return list<TValue>
614618
*/
615619
public function toList(): array
616620
{
@@ -653,7 +657,7 @@ public function toArrayPreservingKeys(): array
653657
/**
654658
* Returns all values preserving keys. This is a terminal operation.
655659
*
656-
* @return array<array-key, TOutput>
660+
* @return array<TKey, TValue>
657661
*/
658662
public function toAssoc(): array
659663
{
@@ -678,8 +682,8 @@ public function toAssoc(): array
678682
*
679683
* @param-out int $count
680684
*
681-
* @phpstan-self-out self<TOutput>
682-
* @return Standard<TOutput>
685+
* @phpstan-self-out self<TKey, TValue>
686+
* @return Standard<TKey, TValue>
683687
*/
684688
public function runningCount(
685689
?int &$count
@@ -720,8 +724,8 @@ public function count(): int
720724
/**
721725
* Converts the pipeline to a non-rewindable stream.
722726
*
723-
* @phpstan-self-out self<TOutput>
724-
* @return Standard<TOutput>
727+
* @phpstan-self-out self<TKey, TValue>
728+
* @return Standard<TKey, TValue>
725729
*/
726730
public function stream()
727731
{
@@ -752,8 +756,8 @@ private static function generatorFromIterable(iterable $input): Generator
752756
* @param int $offset If offset is non-negative, the sequence will start at that offset. If offset is negative, the sequence will start that far from the end.
753757
* @param ?int $length If length is given and is positive, then the sequence will have up to that many elements in it. If length is given and is negative then the sequence will stop that many elements from the end.
754758
*
755-
* @phpstan-self-out self<TOutput>
756-
* @return Standard<TOutput>
759+
* @phpstan-self-out self<TKey, TValue>
760+
* @return Standard<TKey, TValue>
757761
*/
758762
public function slice(int $offset, ?int $length = null)
759763
{
@@ -893,8 +897,8 @@ private static function head(iterable $input, int $length): Iterator
893897
* array_map with first argument set to null. Also known as transposition.
894898
*
895899
* @param iterable<mixed> ...$inputs
896-
* @phpstan-self-out self<array{TOutput, ...}>
897-
* @return Standard<array{TOutput, ...}>
900+
* @phpstan-self-out self<TKey, array{TValue, ...}>
901+
* @return Standard<TKey, array{TValue, ...}>
898902
*/
899903
public function zip(iterable ...$inputs)
900904
{
@@ -1082,7 +1086,7 @@ private static function random(): float
10821086
/**
10831087
* Finds the lowest value using the standard comparison rules. Returns null for empty sequences.
10841088
*
1085-
* @return null|mixed
1089+
* @return null|TValue
10861090
*/
10871091
public function min()
10881092
{
@@ -1120,7 +1124,7 @@ public function min()
11201124
/**
11211125
* Finds the highest value using the standard comparison rules. Returns null for empty sequences.
11221126
*
1123-
* @return null|mixed
1127+
* @return null|TValue
11241128
*/
11251129
public function max()
11261130
{
@@ -1150,8 +1154,8 @@ public function max()
11501154
/**
11511155
* Extracts only the values from the pipeline, discarding keys.
11521156
*
1153-
* @phpstan-self-out self<TOutput>
1154-
* @return Standard<TOutput>
1157+
* @phpstan-self-out self<TKey, TValue>
1158+
* @return Standard<TKey, TValue>
11551159
*/
11561160
public function values()
11571161
{
@@ -1181,8 +1185,8 @@ private static function valuesOnly(iterable $previous): Generator
11811185
/**
11821186
* Extracts only the keys from the pipeline, discarding values.
11831187
*
1184-
* @phpstan-self-out self<array-key>
1185-
* @return Standard<array-key>
1188+
* @phpstan-self-out self<array-key, TKey>
1189+
* @return Standard<array-key, TKey>
11861190
*/
11871191
public function keys()
11881192
{
@@ -1213,8 +1217,8 @@ private static function keysOnly(iterable $previous): Generator
12131217
* Swaps keys and values in the pipeline.
12141218
* The new values will be the original keys, and the new keys will be the original values.
12151219
*
1216-
* @phpstan-self-out self<array-key>&IteratorAggregate<TOutput, array-key>
1217-
* @return Standard<array-key>&IteratorAggregate<TOutput, array-key>
1220+
* @phpstan-self-out self<TValue, TKey>
1221+
* @return Standard<TValue, TKey>
12181222
*/
12191223
public function flip()
12201224
{
@@ -1244,8 +1248,8 @@ private static function flipKeysAndValues(iterable $previous): Generator
12441248
/**
12451249
* Converts each key-value pair into a tuple [key, value].
12461250
*
1247-
* @phpstan-self-out self<array{0: array-key, 1: TOutput}>
1248-
* @return Standard<array{0: array-key, 1: TOutput}>
1251+
* @phpstan-self-out self<array-key, array{0: TKey, 1: TValue}>
1252+
* @return Standard<array-key, array{0: TKey, 1: TValue}>
12491253
*/
12501254
public function tuples()
12511255
{
@@ -1277,7 +1281,7 @@ private static function toTuples(iterable $previous): Generator
12771281
}
12781282
}
12791283

1280-
/** @return self<TOutput> */
1284+
/** @return self<TKey, TValue> */
12811285
private function feedRunningVariance(Helper\RunningVariance $variance, ?callable $castFunc): self
12821286
{
12831287
if (null === $castFunc) {
@@ -1305,8 +1309,8 @@ private function feedRunningVariance(Helper\RunningVariance $variance, ?callable
13051309
*
13061310
* @param-out Helper\RunningVariance $variance
13071311
*
1308-
* @phpstan-self-out self<TOutput>
1309-
* @return Standard<TOutput>
1312+
* @phpstan-self-out self<TKey, TValue>
1313+
* @return Standard<TKey, TValue>
13101314
*/
13111315
public function runningVariance(
13121316
?Helper\RunningVariance &$variance,

src/functions.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
use Generator;
2424

2525
/**
26+
* @template TMapKey
2627
* @template TMapValue
27-
* @param null|(callable(): (TMapValue|Generator<array-key, TMapValue, mixed, mixed>)) $func
28-
* @return Standard<TMapValue>
28+
* @param null|(callable(): (TMapValue|Generator<TMapKey, TMapValue, mixed, mixed>)) $func
29+
* @return Standard<TMapKey, TMapValue>
2930
*/
3031
function map(?callable $func = null): Standard
3132
{
@@ -39,10 +40,11 @@ function map(?callable $func = null): Standard
3940
}
4041

4142
/**
43+
* @template TKey
4244
* @template TTake
43-
* @param null|iterable<TTake> $input
44-
* @param iterable<TTake> ...$inputs
45-
* @return Standard<TTake>
45+
* @param null|iterable<TKey, TTake> $input
46+
* @param iterable<TKey, TTake> ...$inputs
47+
* @return Standard<TKey, TTake>
4648
*/
4749
function take(?iterable $input = null, iterable ...$inputs): Standard
4850
{
@@ -58,7 +60,7 @@ function take(?iterable $input = null, iterable ...$inputs): Standard
5860
/**
5961
* @template T
6062
* @param array<T> $input
61-
* @return Standard<T>
63+
* @return Standard<array-key, T>
6264
*/
6365
function fromArray(array $input): Standard
6466
{
@@ -68,7 +70,7 @@ function fromArray(array $input): Standard
6870
/**
6971
* @template TValue
7072
* @param TValue ...$values
71-
* @return Standard<TValue>
73+
* @return Standard<array-key, TValue>
7274
*/
7375
function fromValues(...$values): Standard
7476
{
@@ -78,7 +80,7 @@ function fromValues(...$values): Standard
7880
/**
7981
* @param iterable<mixed> $base
8082
* @param iterable<mixed> ...$inputs
81-
* @return Standard<array<int, mixed>>
83+
* @return Standard<array-key, array<int, mixed>>
8284
*/
8385
function zip(iterable $base, iterable ...$inputs): Standard
8486
{

0 commit comments

Comments
 (0)