psalm
psalm copied to clipboard
Type parameters for class_alias
There are currently no true type aliases in PHP. Except class_alias
: https://3v4l.org/kVf0M
But class_alias
cannot have any type parameters.
I can't write code like this:
<?php
declare(strict_types=1);
/**
* @template K
* @template V
*/
final class Map {
/**
* @param list<array{K, V}> $paris
*/
public function __construct(
array $paris = [],
) {
}
}
final class Uuid {}
/**
* @template T
* @class-alias Map<Uuid, T>
*/
class_alias(Map::class, UuidMap::class);
/**
* @param UuidMap<int> $_uuidMap
*/
function gimmeUuidMap(UuidMap $_uuidMap): void
{
}
(on psalm.dev: https://psalm.dev/r/73fbe474ad)
It was great to support this in the psalm! I can try to do this. Do you want to stop me?
I found these snippets:
https://psalm.dev/r/73fbe474ad
<?php
declare(strict_types=1);
/**
* @template K
* @template V
*/
final class Map {
/**
* @param list<array{K, V}> $paris
*/
public function __construct(
array $paris = [],
) {
}
}
final class Uuid {}
/**
* @template T
* @class-alias Map<Uuid, T>
*/
class_alias(Map::class, UuidMap::class);
/**
* @param UuidMap<int> $_uuidMap
*/
function gimmeUuidMap(UuidMap $_uuidMap): void
{
}
Psalm output (using commit 3600d51):
ERROR: MissingTemplateParam - 28:11 - Map has missing template params, expecting 2
To me, it looks way more complex than https://psalm.dev/r/75732c0bf7
I found these snippets:
https://psalm.dev/r/75732c0bf7
<?php
declare(strict_types=1);
/**
* @template K
* @template V
*/
class Map {
/**
* @param list<array{K, V}> $pairs
*/
public function __construct(
array $pairs = [],
) {
}
}
final class Uuid {}
/**
* @template T
* @extends Map<Uuid,T>
*/
final class UuidMap extends Map {}
/**
* @param UuidMap<int> $_uuidMap
*/
function gimmeUuidMap(UuidMap $_uuidMap): void
{
}
Psalm output (using commit 3600d51):
No issues!
@weirdan With your code, I can't pass Map<Uuid, int>
to gimmeUuidMap
function: https://psalm.dev/r/3b5a4a7d83
With class_alias
it should be possible.
In our codebase we usually use Set<Uuid>
or Vector<Uuid>
.
It was nice for our eyes to get real type aliases and make UuidVector
and UuidSet
.
In many places we could avoid writing phpdoc at all.
This is a "nice to have, but not required" functionality.
I found these snippets:
https://psalm.dev/r/3b5a4a7d83
<?php
declare(strict_types=1);
/**
* @template K
* @template V
*/
class Map {
/**
* @param list<array{K, V}> $pairs
*/
public function __construct(
array $pairs = [],
) {
}
}
final class Uuid {}
/**
* @template T
* @extends Map<Uuid,T>
*/
final class UuidMap extends Map {}
/**
* @param UuidMap<int> $_uuidMap
*/
function gimmeUuidMap(UuidMap $_uuidMap): void
{
}
/** @var Map<Uuid, int> */
$uuidMap = new Map();
gimmeUuidMap($uuidMap);
Psalm output (using commit 3600d51):
ERROR: ArgumentTypeCoercion - 36:14 - Argument 1 of gimmeUuidMap expects UuidMap<int>, but parent type Map<Uuid, int> provided
Ah, I see. I would probably reject such a PR to Psalm. Alias handling in Psalm has its issues, and so do generics. Combining them sounds like a maintenance pain for a little gain.