Motivation
TypedDataCollection carries its item type via the #[DataCollection(UserData::class)] attribute, and IDEs infer it — but PHPStan/Psalm at strict levels can't, so users with static analysis see mixed (or false positives) on ->first(), ->filter() callbacks, etc. That's a common deal-breaker when evaluating a DTO package.
Proposal
A phpstan-extension (separate package or extension.neon shipped here) that:
- Reads the
#[DataCollection] attribute on the property and types the collection as TypedDataCollection<UserData>
- Types
BaseData::from() / tryFrom() / fromLazy() returns as static (if generics on the base class don't already cover it)
- Types
lazyCollection() item type the same way
A Psalm plugin can follow the same shape later.
Where to look
src/Attributes/DataCollection.php, src/TypedDataCollection.php
- Prior art: phpstan extensions of other collection libraries (dynamic return type extensions + property type extensions)
Happy to mentor this one — comment here if you want to pick it up and we'll agree on the scope first.
Motivation
TypedDataCollectioncarries its item type via the#[DataCollection(UserData::class)]attribute, and IDEs infer it — but PHPStan/Psalm at strict levels can't, so users with static analysis seemixed(or false positives) on->first(),->filter()callbacks, etc. That's a common deal-breaker when evaluating a DTO package.Proposal
A
phpstan-extension(separate package orextension.neonshipped here) that:#[DataCollection]attribute on the property and types the collection asTypedDataCollection<UserData>BaseData::from()/tryFrom()/fromLazy()returns asstatic(if generics on the base class don't already cover it)lazyCollection()item type the same wayA Psalm plugin can follow the same shape later.
Where to look
src/Attributes/DataCollection.php,src/TypedDataCollection.phpHappy to mentor this one — comment here if you want to pick it up and we'll agree on the scope first.