vimeo / psalm

A static analysis tool for finding errors in PHP applications
https://psalm.dev
MIT License
5.55k stars 659 forks source link

Allow templates for type aliases #4308

Open jsiefer opened 4 years ago

jsiefer commented 4 years ago

It would be nice if one could uses templates in type alias. Is that doable? Or is there something similar to solves bellow problem?

/**
 * @template TKey
 * @template TValue
 * @psalm-type array-like=array<TKey, TValue>|ArrayAccess<TKey, TValue>&iterable<TKey, TValue>
 */

/*
 * @var array-like<int, object> $test
 */
$test = [];

https://psalm.dev/r/a357fb65ab

muglug commented 4 years ago

I think the syntax would have to be something like

/**
 * @psalm-type array-like<TKey as array-key, TValue>
 *             = array<TKey, TValue>|ArrayAccess<TKey, TValue>&iterable<TKey, TValue>
 */
muglug commented 4 years ago

I can definitely see the value, albeit in a few very specific settings

jsiefer commented 4 years ago

I am just evaluating psalm for our codebase and that is a scenario that occurs quite often. We allow basic structures using array, but in some impl. we use "array-like" impl. for lazy loading purpose.

Would be nice if you could create your own types. But a simple array-like pseudo type would already work for many cases.

I tried making a plugin for this the other night, but could not quite get my head around completely. Is there a chance you could point me in the right direction what hook to use for hat?

muglug commented 4 years ago

@jsiefer there isn't a plugin hook for the type-expander or type parser to register new types.

It's tangential to the main issue, but I like the idea enough that I've just added support (in the next major version, coming probably later this month) for a shortcut

arraylike-object<K,V> => Traversable<K,V>&ArrayAccess<K,V>

See it here: https://psalm.dev/r/ce6ed6785e

This means you could express your types as array<K,V>|arraylike-object<K,V>, saving a bit of typing.

psalm-github-bot[bot] commented 4 years ago

I found these snippets:

https://psalm.dev/r/ce6ed6785e ```php |array $a */ function test($a): string { return $a[0] ?? ''; } test(['a', 'b']); test(new ArrayObject(['a', 'b'])); ``` ``` Psalm output (using commit 5743471): No issues! ```
jsiefer commented 4 years ago

@muglug Cool, thanks! In multi-dimension arrays this becomes quite difficult to type out otherwise ;)

greg0ire commented 1 year ago

I have another use-case for templating inside aliases: https://psalm.dev/r/e8a0c150cf

psalm-github-bot[bot] commented 1 year ago

I found these snippets:

https://psalm.dev/r/e8a0c150cf ```php */ private array $tokens = []; } ``` ``` Psalm output (using commit c3cc906): ERROR: UndefinedDocblockClass - 14:13 - Docblock-defined class, interface or enum named RequiredForTheBugToAppear\T does not exist ERROR: UndefinedDocblockClass - 14:5 - Docblock-defined class, interface or enum named RequiredForTheBugToAppear\T does not exist ```