psalm
psalm copied to clipboard
Merging object-like arrays on imported type does not work
Using intersection types, it is possible to extend array shapes as described here.
This works fine:
<?php
/**
* @psalm-type SaveData = array{name: string}
* @psalm-type ExtSaveData = SaveData & array{id:string}
*/
Class Test1 {
}
However, if I want to do the same when one of the types is imported from another file, I get an error from psalm:
/********** FILE Test1.php **********/
<?php
/**
* @psalm-type SaveData = array{name: string}
*/
Class Test1 {
}
/********** FILE Test2.php **********/
<?php
/**
* @psalm-import-type SaveData from Test1
* @psalm-type ExtSaveData = SaveData & array{id:string}
*/
Class Test2 {
}
This will produce the following error:
ERROR: InvalidDocblock - Test2.php:8:1 - Intersection types must be all objects, Psalm\Type\Atomic\TKeyedArray provided (see https://psalm.dev/008)
/**
* @psalm-import-type SaveData from Test1
* @psalm-type ExtSaveData = SaveData & array{id:string}
*/
Class Test2 {
I have encountered this as well :(
Looks like this is the same as https://github.com/vimeo/psalm/issues/9603 - see (temporary) "as" fix on that issue
Another very similar example: https://psalm.dev/r/82a8ee14d5
I found these snippets:
https://psalm.dev/r/82a8ee14d5
<?php
namespace A {
/**
* @psalm-type AType = array{test: string}
*/
class AAA {
}
}
namespace B {
/**
* @psalm-import-type AType from \A\AAA
* @psalm-type BType = array{anotherTest: string}
* @psalm-type Compound = AType&BType
*/
class BBB {
/**
* @param Compound $type
*/
public function useCompoundType($type): void
{
/** @psalm-trace $type */
return;
}
}
}
Psalm output (using commit 67d6468):
ERROR: InvalidDocblock - 17:3 - The intersection type must not mix array and object types!
ERROR: UndefinedDocblockClass - 19:15 - Docblock-defined class, interface or enum named B\Compound does not exist
Another one, with minimalistic annotation. https://psalm.dev/r/bce2b8edcb
I found these snippets:
https://psalm.dev/r/bce2b8edcb
<?php
/**
* @psalm-type TBaseConfiguration=array{type?: string, ...<string, mixed>}
* @psalm-type TConfiguration=array{name: string}&TBaseConfiguration
*/
class Working2 {}
/** @psalm-type TBaseConfiguration=array{type?: string, ...<string, mixed>} */
class BaseClass {}
/**
* @psalm-import-type TBaseConfiguration from BaseClass
* @psalm-type TConfiguration=array{name: string}&TBaseConfiguration
*/
class BrokenDueToImportedType1 {}
Psalm output (using commit 08afc45):
ERROR: InvalidDocblock - 16:1 - Intersection types must be all objects or all keyed array.